From adf1a10e0ee7626c28cd796856ca9e2144b25d64 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 24 May 2023 15:15:14 -0500 Subject: [PATCH 001/148] Create control hub module --- package-lock.json | 68 ++++ packages/control-hub/package.json | 18 + packages/control-hub/src/index.ts | 0 .../control-hub/src/internal/ControlHub.ts | 341 ++++++++++++++++++ .../control-hub/src/internal/discovery.ts | 18 + packages/control-hub/tsconfig.json | 8 + packages/expansion-hub/src/RevHubType.ts | 4 +- 7 files changed, 455 insertions(+), 2 deletions(-) create mode 100644 packages/control-hub/package.json create mode 100644 packages/control-hub/src/index.ts create mode 100644 packages/control-hub/src/internal/ControlHub.ts create mode 100644 packages/control-hub/src/internal/discovery.ts create mode 100644 packages/control-hub/tsconfig.json diff --git a/package-lock.json b/package-lock.json index cf703656..2aa58ea1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1786,6 +1786,10 @@ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true }, + "node_modules/@rev-robotics/control-hub": { + "resolved": "packages/control-hub", + "link": true + }, "node_modules/@rev-robotics/expansion-hub": { "resolved": "packages/expansion-hub", "link": true @@ -4351,6 +4355,14 @@ "node": ">=0.10.0" } }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/jake": { "version": "10.8.5", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", @@ -7803,6 +7815,27 @@ "node": ">=6" } }, + "node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -7863,6 +7896,18 @@ "node": ">=10" } }, + "packages/control-hub": { + "version": "0.1.0", + "dependencies": { + "@rev-robotics/rhsplib": "*", + "isomorphic-ws": "^5.0.0", + "serialport": "^10.5.0" + }, + "devDependencies": { + "@types/node": "^16.18.18", + "typescript": "^5.0.2" + } + }, "packages/expansion-hub": { "name": "@rev-robotics/expansion-hub", "version": "0.1.0", @@ -9285,6 +9330,16 @@ } } }, + "@rev-robotics/control-hub": { + "version": "file:packages/control-hub", + "requires": { + "@rev-robotics/rhsplib": "*", + "@types/node": "^16.18.18", + "isomorphic-ws": "^5.0.0", + "serialport": "^10.5.0", + "typescript": "^5.0.2" + } + }, "@rev-robotics/expansion-hub": { "version": "file:packages/expansion-hub", "requires": { @@ -11247,6 +11302,12 @@ "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true }, + "isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "requires": {} + }, "jake": { "version": "10.8.5", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", @@ -13893,6 +13954,13 @@ } } }, + "ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "peer": true, + "requires": {} + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/packages/control-hub/package.json b/packages/control-hub/package.json new file mode 100644 index 00000000..07e9d25b --- /dev/null +++ b/packages/control-hub/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rev-robotics/control-hub", + "version": "0.1.0", + "description": "High level library for REV control hub", + "main": "dist/index.js", + "dependencies": { + "serialport": "^10.5.0", + "isomorphic-ws": "^5.0.0", + "@rev-robotics/rhsplib": "*" + }, + "devDependencies": { + "@types/node": "^16.18.18", + "typescript": "^5.0.2" + }, + "scripts": { + "build": "tsc" + } +} \ No newline at end of file diff --git a/packages/control-hub/src/index.ts b/packages/control-hub/src/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts new file mode 100644 index 00000000..0d6f24df --- /dev/null +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -0,0 +1,341 @@ +import { + ExpansionHub, + ParentRevHub, + RevHub, +} from "@rev-robotics/expansion-hub"; +import { RevHubType } from "@rev-robotics/expansion-hub/dist/RevHubType"; +import { + BulkInputData, + DebugGroup, + DIODirection, + I2CReadStatus, + I2CSpeedCode, + I2CWriteStatus, + LEDPattern, + ModuleInterface, + ModuleStatus, + PIDCoefficients, + RGB, + VerbosityLevel, + Version, +} from "@rev-robotics/rhsplib"; + +export class ControlHub implements ExpansionHub { + readonly isOpen: boolean = true; + readonly moduleAddress: number = 0; + responseTimeoutMs: number = 0; + type: RevHubType = RevHubType.ControlHub; + + async open() {} + + close(): void {} + + getADC(): Promise { + return Promise.resolve(0); + } + + async getBulkInputData(): Promise { + throw new Error("not implemented"); + } + + getDigitalAllInputs(): Promise { + throw new Error("not implemented"); + } + + async getDigitalDirection(dioPin: number): Promise { + throw new Error("not implemented"); + } + + getDigitalSingleInput(dioPin: number): Promise { + throw new Error("not implemented"); + } + + getFTDIResetControl(): Promise { + throw new Error("not implemented"); + } + + getI2CChannelConfiguration(i2cChannel: number): Promise { + throw new Error("not implemented"); + } + + getI2CReadStatus(i2cChannel: number): Promise { + throw new Error("not implemented"); + } + + getI2CWriteStatus(i2cChannel: number): Promise { + throw new Error("not implemented"); + } + + getInterfacePacketID( + interfaceName: string, + functionNumber: number + ): Promise { + return Promise.resolve(0); + } + + getModuleLEDColor(): Promise { + throw new Error("not implemented"); + } + + getModuleLEDPattern(): Promise { + throw new Error("not implemented"); + } + + getModuleStatus(clearStatusAfterResponse: boolean): Promise { + throw new Error("not implemented"); + } + + getMotorAtTarget(motorChannel: number): Promise { + return Promise.resolve(false); + } + + getMotorChannelCurrentAlertLevel(motorChannel: number): Promise { + return Promise.resolve(0); + } + + getMotorChannelEnable(motorChannel: number): Promise { + return Promise.resolve(false); + } + + getMotorChannelMode( + motorChannel: number + ): Promise<{ motorMode: number; floatAtZero: boolean }> { + return Promise.resolve({ floatAtZero: false, motorMode: 0 }); + } + + getMotorConstantPower(motorChannel: number): Promise { + return Promise.resolve(0); + } + + getMotorEncoderPosition(motorChannel: number): Promise { + return Promise.resolve(0); + } + + getMotorPIDCoefficients( + motorChannel: number, + motorMode: number + ): Promise { + throw new Error("not implemented"); + } + + getMotorTargetPosition( + motorChannel: number + ): Promise<{ targetPosition: number; targetTolerance: number }> { + return Promise.resolve({ targetPosition: 0, targetTolerance: 0 }); + } + + getMotorTargetVelocity(motorChannel: number): Promise { + return Promise.resolve(0); + } + + getPhoneChargeControl(): Promise { + return Promise.resolve(false); + } + + getServoConfiguration(servoChannel: number): Promise { + return Promise.resolve(0); + } + + getServoEnable(servoChannel: number): Promise { + return Promise.resolve(false); + } + + getServoPulseWidth(servoChannel: number): Promise { + return Promise.resolve(0); + } + + injectDataLogHint(hintText: string): Promise { + throw new Error("not implemented"); + } + + isExpansionHub(): this is ExpansionHub { + throw new Error("not implemented"); + } + + isParent(): this is ParentRevHub { + throw new Error("not implemented"); + } + + on(eventName: "error", listener: (error: Error) => void): RevHub { + throw new Error("not implemented"); + } + + queryInterface(interfaceName: string): Promise { + throw new Error("not implemented"); + } + + readI2CMultipleBytes( + i2cChannel: number, + slaveAddress: number, + numBytesToRead: number + ): Promise { + throw new Error("not implemented"); + } + + readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise { + throw new Error("not implemented"); + } + + readVersion(): Promise { + throw new Error("not implemented"); + } + + readVersionString(): Promise { + return Promise.resolve(""); + } + + resetMotorEncoder(motorChannel: number): Promise { + throw new Error("not implemented"); + } + + sendFailSafe(): Promise { + throw new Error("not implemented"); + } + + sendKeepAlive(): Promise { + throw new Error("not implemented"); + } + + sendReadCommand(packetTypeID: number, payload: number[]): Promise { + return Promise.resolve([]); + } + + sendWriteCommand(packetTypeID: number, payload: number[]): Promise { + return Promise.resolve([]); + } + + setDebugLogLevel( + debugGroup: DebugGroup, + verbosityLevel: VerbosityLevel + ): Promise { + throw new Error("not implemented"); + } + + setDigitalAllOutputs(bitPackedField: number): Promise { + throw new Error("not implemented"); + } + + setDigitalDirection(dioPin: number, direction: DIODirection): Promise { + throw new Error("not implemented"); + } + + setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { + throw new Error("not implemented"); + } + + setFTDIResetControl(ftdiResetControl: boolean): Promise { + throw new Error("not implemented"); + } + + setI2CChannelConfiguration( + i2cChannel: number, + speedCode: I2CSpeedCode + ): Promise { + throw new Error("not implemented"); + } + + setModuleLEDColor(red: number, green: number, blue: number): Promise { + throw new Error("not implemented"); + } + + setModuleLEDPattern(ledPattern: LEDPattern): Promise { + throw new Error("not implemented"); + } + + setMotorChannelCurrentAlertLevel( + motorChannel: number, + currentLimit_mA: number + ): Promise { + throw new Error("not implemented"); + } + + setMotorChannelEnable(motorChannel: number, enable: boolean): Promise { + throw new Error("not implemented"); + } + + setMotorChannelMode( + motorChannel: number, + motorMode: number, + floatAtZero: boolean + ): Promise { + throw new Error("not implemented"); + } + + setMotorConstantPower( + motorChannel: number, + powerLevel: number + ): Promise { + throw new Error("not implemented"); + } + + setMotorPIDCoefficients( + motorChannel: number, + motorMode: number, + pid: PIDCoefficients + ): Promise { + throw new Error("not implemented"); + } + + setMotorTargetPosition( + motorChannel: number, + targetPosition_counts: number, + targetTolerance_counts: number + ): Promise { + throw new Error("not implemented"); + } + + setMotorTargetVelocity( + motorChannel: number, + velocity_cps: number + ): Promise { + throw new Error("not implemented"); + } + + setNewModuleAddress(newModuleAddress: number): Promise { + throw new Error("not implemented"); + } + + setPhoneChargeControl(chargeEnable: boolean): Promise { + throw new Error("not implemented"); + } + + setServoConfiguration( + servoChannel: number, + framePeriod: number + ): Promise { + throw new Error("not implemented"); + } + + setServoEnable(servoChannel: number, enable: boolean): Promise { + throw new Error("not implemented"); + } + + setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise { + throw new Error("not implemented"); + } + + writeI2CMultipleBytes( + i2cChannel: number, + slaveAddress: number, + bytes: number[] + ): Promise { + throw new Error("not implemented"); + } + + writeI2CReadMultipleBytes( + i2cChannel: number, + slaveAddress: number, + numBytesToRead: number, + startAddress: number + ): Promise { + throw new Error("not implemented"); + } + + writeI2CSingleByte( + i2cChannel: number, + slaveAddress: number, + byte: number + ): Promise { + throw new Error("not implemented"); + } +} diff --git a/packages/control-hub/src/internal/discovery.ts b/packages/control-hub/src/internal/discovery.ts new file mode 100644 index 00000000..c58d2d5d --- /dev/null +++ b/packages/control-hub/src/internal/discovery.ts @@ -0,0 +1,18 @@ +import { ControlHub } from "./ControlHub"; + +export async function getConnectedControlHub(): Promise< + ControlHub | undefined +> { + try { + return await createControlHub(); + } catch (e: any) { + return undefined; + } +} + +async function createControlHub(): Promise { + let hub = new ControlHub(); + await hub.open(); + + return hub; +} diff --git a/packages/control-hub/tsconfig.json b/packages/control-hub/tsconfig.json new file mode 100644 index 00000000..4a3682c7 --- /dev/null +++ b/packages/control-hub/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "target": "es2017" + } +} diff --git a/packages/expansion-hub/src/RevHubType.ts b/packages/expansion-hub/src/RevHubType.ts index 55216aee..b40e5d0f 100644 --- a/packages/expansion-hub/src/RevHubType.ts +++ b/packages/expansion-hub/src/RevHubType.ts @@ -1,4 +1,4 @@ - export enum RevHubType { - ExpansionHub + ExpansionHub, + ControlHub, } From aa4125d61e9f959ed486c687446b8b9b02f49f93 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 13:58:40 -0500 Subject: [PATCH 002/148] Try to connect to control hub --- packages/control-hub/package.json | 1 + .../control-hub/src/internal/ControlHub.ts | 21 ++++++++++++++++++- .../control-hub/src/internal/discovery.ts | 5 +++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/control-hub/package.json b/packages/control-hub/package.json index 07e9d25b..fedd1e66 100644 --- a/packages/control-hub/package.json +++ b/packages/control-hub/package.json @@ -6,6 +6,7 @@ "dependencies": { "serialport": "^10.5.0", "isomorphic-ws": "^5.0.0", + "axios":"^1.4.0", "@rev-robotics/rhsplib": "*" }, "devDependencies": { diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 0d6f24df..fc3873c8 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -19,14 +19,33 @@ import { VerbosityLevel, Version, } from "@rev-robotics/rhsplib"; +import axios from "axios"; export class ControlHub implements ExpansionHub { readonly isOpen: boolean = true; readonly moduleAddress: number = 0; responseTimeoutMs: number = 0; type: RevHubType = RevHubType.ControlHub; + webSocketConnection?: WebSocket; - async open() {} + async open() { + this.webSocketConnection = new WebSocket("ws://192.168.43.1:8081"); + } + + async isConnected(): Promise { + try { + let response = await axios.get("http://192.168.43.1:8080/js/rcInfo.json"); + if(response.data) { + let rcInfo = JSON.parse(response.data); + console.log(rcInfo); + return rcInfo.webSocketApiVersion == "1"; + } + + return false; + } catch (e) { + return false; + } + } close(): void {} diff --git a/packages/control-hub/src/internal/discovery.ts b/packages/control-hub/src/internal/discovery.ts index c58d2d5d..f8311540 100644 --- a/packages/control-hub/src/internal/discovery.ts +++ b/packages/control-hub/src/internal/discovery.ts @@ -12,6 +12,11 @@ export async function getConnectedControlHub(): Promise< async function createControlHub(): Promise { let hub = new ControlHub(); + + if(!await hub.isConnected()) { + throw new Error("Hub is not connected via WiFi"); + } + await hub.open(); return hub; From c9234227b031a69fc328025b63048352d11a406d Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 14:12:02 -0500 Subject: [PATCH 003/148] Try to connect to control hub --- packages/control-hub/src/{internal => }/discovery.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/control-hub/src/{internal => }/discovery.ts (100%) diff --git a/packages/control-hub/src/internal/discovery.ts b/packages/control-hub/src/discovery.ts similarity index 100% rename from packages/control-hub/src/internal/discovery.ts rename to packages/control-hub/src/discovery.ts From 4d227a2da34963b0b631ee03e9aa08dc1c9e6343 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 16:25:41 -0500 Subject: [PATCH 004/148] Get module address of hub connected over wifi --- package-lock.json | 65 +- packages/control-hub/src/discovery.ts | 6 +- packages/control-hub/src/index.ts | 2 + .../control-hub/src/internal/ControlHub.ts | 750 +++++++++--------- packages/control-hub/tsconfig.json | 1 + packages/sample/package.json | 4 + packages/sample/src/command/list.ts | 17 +- 7 files changed, 454 insertions(+), 391 deletions(-) diff --git a/package-lock.json b/package-lock.json index b9ef3702..9ddc925d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2373,6 +2373,15 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "node_modules/@types/ws": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -2598,8 +2607,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/at-least-node": { "version": "1.0.0", @@ -2614,7 +2622,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", - "dev": true, "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -3005,7 +3012,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3364,7 +3370,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -3765,7 +3770,6 @@ "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "dev": true, "funding": [ { "type": "individual", @@ -3785,7 +3789,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -5593,7 +5596,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -5602,7 +5604,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -7025,8 +7026,7 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/pump": { "version": "3.0.0", @@ -8421,7 +8421,6 @@ "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "peer": true, "engines": { "node": ">=10.0.0" }, @@ -8499,9 +8498,11 @@ } }, "packages/control-hub": { + "name": "@rev-robotics/control-hub", "version": "0.1.0", "dependencies": { "@rev-robotics/rhsplib": "*", + "axios": "^1.4.0", "isomorphic-ws": "^5.0.0", "serialport": "^10.5.0" }, @@ -8542,7 +8543,11 @@ "version": "0.1.0", "dependencies": { "@rev-robotics/expansion-hub": "*", - "commander": "^10.0.1" + "commander": "^10.0.1", + "ws": "8.13.0" + }, + "devDependencies": { + "@types/ws": "^8.5.4" } } }, @@ -10171,6 +10176,7 @@ "requires": { "@rev-robotics/rhsplib": "*", "@types/node": "^16.18.18", + "axios": "^1.4.0", "isomorphic-ws": "^5.0.0", "serialport": "^10.5.0", "typescript": "^5.0.2" @@ -10327,6 +10333,15 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/ws": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -10506,8 +10521,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "at-least-node": { "version": "1.0.0", @@ -10519,7 +10533,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", - "dev": true, "requires": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -10814,7 +10827,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -11092,8 +11104,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "delegates": { "version": "1.0.0", @@ -11408,14 +11419,12 @@ "follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "dev": true + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" }, "form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -12813,14 +12822,12 @@ "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "requires": { "mime-db": "1.52.0" } @@ -13895,8 +13902,7 @@ "proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "pump": { "version": "3.0.0", @@ -14234,7 +14240,9 @@ "version": "file:packages/sample", "requires": { "@rev-robotics/expansion-hub": "*", - "commander": "^10.0.1" + "@types/ws": "^8.5.4", + "commander": "^10.0.1", + "ws": "8.13.0" } }, "semver": { @@ -14968,7 +14976,6 @@ "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "peer": true, "requires": {} }, "xtend": { diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index f8311540..53ce4169 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -1,11 +1,12 @@ -import { ControlHub } from "./ControlHub"; +import { ControlHub } from "./internal/ControlHub"; -export async function getConnectedControlHub(): Promise< +export async function openConnectedControlHub(): Promise< ControlHub | undefined > { try { return await createControlHub(); } catch (e: any) { + console.log(e); return undefined; } } @@ -14,6 +15,7 @@ async function createControlHub(): Promise { let hub = new ControlHub(); if(!await hub.isConnected()) { + console.log("Hub not connected") throw new Error("Hub is not connected via WiFi"); } diff --git a/packages/control-hub/src/index.ts b/packages/control-hub/src/index.ts index e69de29b..e5d405df 100644 --- a/packages/control-hub/src/index.ts +++ b/packages/control-hub/src/index.ts @@ -0,0 +1,2 @@ + +export * from './discovery'; \ No newline at end of file diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index fc3873c8..0da915ae 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -1,360 +1,404 @@ -import { - ExpansionHub, - ParentRevHub, - RevHub, -} from "@rev-robotics/expansion-hub"; +import { ExpansionHub, ParentRevHub, RevHub } from "@rev-robotics/expansion-hub"; import { RevHubType } from "@rev-robotics/expansion-hub/dist/RevHubType"; import { - BulkInputData, - DebugGroup, - DIODirection, - I2CReadStatus, - I2CSpeedCode, - I2CWriteStatus, - LEDPattern, - ModuleInterface, - ModuleStatus, - PIDCoefficients, - RGB, - VerbosityLevel, - Version, + BulkInputData, + DebugGroup, + DIODirection, + I2CReadStatus, + I2CSpeedCode, + I2CWriteStatus, + LEDPattern, + ModuleInterface, + ModuleStatus, + PIDCoefficients, + RGB, + VerbosityLevel, + Version, } from "@rev-robotics/rhsplib"; import axios from "axios"; +import WebSocket from "isomorphic-ws"; export class ControlHub implements ExpansionHub { - readonly isOpen: boolean = true; - readonly moduleAddress: number = 0; - responseTimeoutMs: number = 0; - type: RevHubType = RevHubType.ControlHub; - webSocketConnection?: WebSocket; - - async open() { - this.webSocketConnection = new WebSocket("ws://192.168.43.1:8081"); - } - - async isConnected(): Promise { - try { - let response = await axios.get("http://192.168.43.1:8080/js/rcInfo.json"); - if(response.data) { - let rcInfo = JSON.parse(response.data); - console.log(rcInfo); - return rcInfo.webSocketApiVersion == "1"; - } - - return false; - } catch (e) { - return false; - } - } - - close(): void {} - - getADC(): Promise { - return Promise.resolve(0); - } - - async getBulkInputData(): Promise { - throw new Error("not implemented"); - } - - getDigitalAllInputs(): Promise { - throw new Error("not implemented"); - } - - async getDigitalDirection(dioPin: number): Promise { - throw new Error("not implemented"); - } - - getDigitalSingleInput(dioPin: number): Promise { - throw new Error("not implemented"); - } - - getFTDIResetControl(): Promise { - throw new Error("not implemented"); - } - - getI2CChannelConfiguration(i2cChannel: number): Promise { - throw new Error("not implemented"); - } - - getI2CReadStatus(i2cChannel: number): Promise { - throw new Error("not implemented"); - } - - getI2CWriteStatus(i2cChannel: number): Promise { - throw new Error("not implemented"); - } - - getInterfacePacketID( - interfaceName: string, - functionNumber: number - ): Promise { - return Promise.resolve(0); - } - - getModuleLEDColor(): Promise { - throw new Error("not implemented"); - } - - getModuleLEDPattern(): Promise { - throw new Error("not implemented"); - } - - getModuleStatus(clearStatusAfterResponse: boolean): Promise { - throw new Error("not implemented"); - } - - getMotorAtTarget(motorChannel: number): Promise { - return Promise.resolve(false); - } - - getMotorChannelCurrentAlertLevel(motorChannel: number): Promise { - return Promise.resolve(0); - } - - getMotorChannelEnable(motorChannel: number): Promise { - return Promise.resolve(false); - } - - getMotorChannelMode( - motorChannel: number - ): Promise<{ motorMode: number; floatAtZero: boolean }> { - return Promise.resolve({ floatAtZero: false, motorMode: 0 }); - } - - getMotorConstantPower(motorChannel: number): Promise { - return Promise.resolve(0); - } - - getMotorEncoderPosition(motorChannel: number): Promise { - return Promise.resolve(0); - } - - getMotorPIDCoefficients( - motorChannel: number, - motorMode: number - ): Promise { - throw new Error("not implemented"); - } - - getMotorTargetPosition( - motorChannel: number - ): Promise<{ targetPosition: number; targetTolerance: number }> { - return Promise.resolve({ targetPosition: 0, targetTolerance: 0 }); - } - - getMotorTargetVelocity(motorChannel: number): Promise { - return Promise.resolve(0); - } - - getPhoneChargeControl(): Promise { - return Promise.resolve(false); - } - - getServoConfiguration(servoChannel: number): Promise { - return Promise.resolve(0); - } - - getServoEnable(servoChannel: number): Promise { - return Promise.resolve(false); - } - - getServoPulseWidth(servoChannel: number): Promise { - return Promise.resolve(0); - } - - injectDataLogHint(hintText: string): Promise { - throw new Error("not implemented"); - } - - isExpansionHub(): this is ExpansionHub { - throw new Error("not implemented"); - } - - isParent(): this is ParentRevHub { - throw new Error("not implemented"); - } - - on(eventName: "error", listener: (error: Error) => void): RevHub { - throw new Error("not implemented"); - } - - queryInterface(interfaceName: string): Promise { - throw new Error("not implemented"); - } - - readI2CMultipleBytes( - i2cChannel: number, - slaveAddress: number, - numBytesToRead: number - ): Promise { - throw new Error("not implemented"); - } - - readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise { - throw new Error("not implemented"); - } - - readVersion(): Promise { - throw new Error("not implemented"); - } - - readVersionString(): Promise { - return Promise.resolve(""); - } - - resetMotorEncoder(motorChannel: number): Promise { - throw new Error("not implemented"); - } - - sendFailSafe(): Promise { - throw new Error("not implemented"); - } - - sendKeepAlive(): Promise { - throw new Error("not implemented"); - } - - sendReadCommand(packetTypeID: number, payload: number[]): Promise { - return Promise.resolve([]); - } - - sendWriteCommand(packetTypeID: number, payload: number[]): Promise { - return Promise.resolve([]); - } - - setDebugLogLevel( - debugGroup: DebugGroup, - verbosityLevel: VerbosityLevel - ): Promise { - throw new Error("not implemented"); - } - - setDigitalAllOutputs(bitPackedField: number): Promise { - throw new Error("not implemented"); - } - - setDigitalDirection(dioPin: number, direction: DIODirection): Promise { - throw new Error("not implemented"); - } - - setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { - throw new Error("not implemented"); - } - - setFTDIResetControl(ftdiResetControl: boolean): Promise { - throw new Error("not implemented"); - } - - setI2CChannelConfiguration( - i2cChannel: number, - speedCode: I2CSpeedCode - ): Promise { - throw new Error("not implemented"); - } - - setModuleLEDColor(red: number, green: number, blue: number): Promise { - throw new Error("not implemented"); - } - - setModuleLEDPattern(ledPattern: LEDPattern): Promise { - throw new Error("not implemented"); - } - - setMotorChannelCurrentAlertLevel( - motorChannel: number, - currentLimit_mA: number - ): Promise { - throw new Error("not implemented"); - } - - setMotorChannelEnable(motorChannel: number, enable: boolean): Promise { - throw new Error("not implemented"); - } - - setMotorChannelMode( - motorChannel: number, - motorMode: number, - floatAtZero: boolean - ): Promise { - throw new Error("not implemented"); - } - - setMotorConstantPower( - motorChannel: number, - powerLevel: number - ): Promise { - throw new Error("not implemented"); - } - - setMotorPIDCoefficients( - motorChannel: number, - motorMode: number, - pid: PIDCoefficients - ): Promise { - throw new Error("not implemented"); - } - - setMotorTargetPosition( - motorChannel: number, - targetPosition_counts: number, - targetTolerance_counts: number - ): Promise { - throw new Error("not implemented"); - } - - setMotorTargetVelocity( - motorChannel: number, - velocity_cps: number - ): Promise { - throw new Error("not implemented"); - } - - setNewModuleAddress(newModuleAddress: number): Promise { - throw new Error("not implemented"); - } - - setPhoneChargeControl(chargeEnable: boolean): Promise { - throw new Error("not implemented"); - } - - setServoConfiguration( - servoChannel: number, - framePeriod: number - ): Promise { - throw new Error("not implemented"); - } - - setServoEnable(servoChannel: number, enable: boolean): Promise { - throw new Error("not implemented"); - } - - setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise { - throw new Error("not implemented"); - } - - writeI2CMultipleBytes( - i2cChannel: number, - slaveAddress: number, - bytes: number[] - ): Promise { - throw new Error("not implemented"); - } - - writeI2CReadMultipleBytes( - i2cChannel: number, - slaveAddress: number, - numBytesToRead: number, - startAddress: number - ): Promise { - throw new Error("not implemented"); - } - - writeI2CSingleByte( - i2cChannel: number, - slaveAddress: number, - byte: number - ): Promise { - throw new Error("not implemented"); - } + readonly isOpen: boolean = true; + moduleAddress: number = 0; + responseTimeoutMs: number = 0; + type: RevHubType = RevHubType.ControlHub; + webSocketConnection!: WebSocket; + + keyGenerator = 0; + currentActiveCommands = new Map< + any, + (response: any | undefined, error: any | undefined) => void + >(); + + async open(): Promise { + this.webSocketConnection = new WebSocket("ws://192.168.43.1:8081"); + + this.webSocketConnection.on("message", (data) => { + let rawMessage = JSON.parse(data.toString()); + + if (rawMessage.key !== undefined) { + let key = rawMessage.key; + let callback = this.currentActiveCommands.get(key); + + let response = rawMessage.response + ? JSON.parse(rawMessage.response) + : undefined; + let error = rawMessage.error ? JSON.parse(rawMessage.error) : undefined; + + if (callback) { + callback(response, error); + } + } + }); + + return new Promise((resolve, reject) => { + this.webSocketConnection.on("open", async () => { + this.moduleAddress = await this.sendCommand("getModuleAddress", {}); + resolve(); + }); + }); + } + + async isConnected(): Promise { + try { + let response = await axios.get("http://192.168.43.1:8080/js/rcInfo.json", { + timeout: 1000, + }); + if (response.data) { + return true; + //return response.data.webSocketApiVersion === "1"; + } + + return false; + } catch (e) { + console.log(e); + return false; + } + } + + close(): void {} + + getADC(): Promise { + return Promise.resolve(0); + } + + async getBulkInputData(): Promise { + throw new Error("not implemented"); + } + + getDigitalAllInputs(): Promise { + throw new Error("not implemented"); + } + + async getDigitalDirection(dioPin: number): Promise { + throw new Error("not implemented"); + } + + getDigitalSingleInput(dioPin: number): Promise { + throw new Error("not implemented"); + } + + getFTDIResetControl(): Promise { + throw new Error("not implemented"); + } + + getI2CChannelConfiguration(i2cChannel: number): Promise { + throw new Error("not implemented"); + } + + getI2CReadStatus(i2cChannel: number): Promise { + throw new Error("not implemented"); + } + + getI2CWriteStatus(i2cChannel: number): Promise { + throw new Error("not implemented"); + } + + getInterfacePacketID(interfaceName: string, functionNumber: number): Promise { + return Promise.resolve(0); + } + + getModuleLedColor(): Promise { + throw new Error("not implemented"); + } + + getModuleLedPattern(): Promise { + throw new Error("not implemented"); + } + + getModuleStatus(clearStatusAfterResponse: boolean): Promise { + throw new Error("not implemented"); + } + + getMotorAtTarget(motorChannel: number): Promise { + return Promise.resolve(false); + } + + getMotorChannelCurrentAlertLevel(motorChannel: number): Promise { + return Promise.resolve(0); + } + + getMotorChannelEnable(motorChannel: number): Promise { + return Promise.resolve(false); + } + + getMotorChannelMode( + motorChannel: number, + ): Promise<{ motorMode: number; floatAtZero: boolean }> { + return Promise.resolve({ floatAtZero: false, motorMode: 0 }); + } + + getMotorConstantPower(motorChannel: number): Promise { + return Promise.resolve(0); + } + + getMotorEncoderPosition(motorChannel: number): Promise { + return Promise.resolve(0); + } + + getMotorPIDCoefficients( + motorChannel: number, + motorMode: number, + ): Promise { + throw new Error("not implemented"); + } + + getMotorTargetPosition( + motorChannel: number, + ): Promise<{ targetPosition: number; targetTolerance: number }> { + return Promise.resolve({ targetPosition: 0, targetTolerance: 0 }); + } + + getMotorTargetVelocity(motorChannel: number): Promise { + return Promise.resolve(0); + } + + getPhoneChargeControl(): Promise { + return Promise.resolve(false); + } + + getServoConfiguration(servoChannel: number): Promise { + return Promise.resolve(0); + } + + getServoEnable(servoChannel: number): Promise { + return Promise.resolve(false); + } + + getServoPulseWidth(servoChannel: number): Promise { + return Promise.resolve(0); + } + + injectDataLogHint(hintText: string): Promise { + throw new Error("not implemented"); + } + + isExpansionHub(): this is ExpansionHub { + throw new Error("not implemented"); + } + + isParent(): this is ParentRevHub { + throw new Error("not implemented"); + } + + on(eventName: "error", listener: (error: Error) => void): RevHub { + throw new Error("not implemented"); + } + + queryInterface(interfaceName: string): Promise { + throw new Error("not implemented"); + } + + readI2CMultipleBytes( + i2cChannel: number, + slaveAddress: number, + numBytesToRead: number, + ): Promise { + throw new Error("not implemented"); + } + + readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise { + throw new Error("not implemented"); + } + + readVersion(): Promise { + throw new Error("not implemented"); + } + + readVersionString(): Promise { + return Promise.resolve(""); + } + + resetMotorEncoder(motorChannel: number): Promise { + throw new Error("not implemented"); + } + + sendFailSafe(): Promise { + throw new Error("not implemented"); + } + + sendKeepAlive(): Promise { + throw new Error("not implemented"); + } + + sendReadCommand(packetTypeID: number, payload: number[]): Promise { + return Promise.resolve([]); + } + + sendWriteCommand(packetTypeID: number, payload: number[]): Promise { + return Promise.resolve([]); + } + + setDebugLogLevel( + debugGroup: DebugGroup, + verbosityLevel: VerbosityLevel, + ): Promise { + throw new Error("not implemented"); + } + + setDigitalAllOutputs(bitPackedField: number): Promise { + throw new Error("not implemented"); + } + + setDigitalDirection(dioPin: number, direction: DIODirection): Promise { + throw new Error("not implemented"); + } + + setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { + throw new Error("not implemented"); + } + + setFTDIResetControl(ftdiResetControl: boolean): Promise { + throw new Error("not implemented"); + } + + setI2CChannelConfiguration( + i2cChannel: number, + speedCode: I2CSpeedCode, + ): Promise { + throw new Error("not implemented"); + } + + setModuleLedColor(red: number, green: number, blue: number): Promise { + throw new Error("not implemented"); + } + + setModuleLedPattern(ledPattern: LEDPattern): Promise { + throw new Error("not implemented"); + } + + setMotorChannelCurrentAlertLevel( + motorChannel: number, + currentLimit_mA: number, + ): Promise { + throw new Error("not implemented"); + } + + setMotorChannelEnable(motorChannel: number, enable: boolean): Promise { + throw new Error("not implemented"); + } + + setMotorChannelMode( + motorChannel: number, + motorMode: number, + floatAtZero: boolean, + ): Promise { + throw new Error("not implemented"); + } + + setMotorConstantPower(motorChannel: number, powerLevel: number): Promise { + throw new Error("not implemented"); + } + + setMotorPIDCoefficients( + motorChannel: number, + motorMode: number, + pid: PIDCoefficients, + ): Promise { + throw new Error("not implemented"); + } + + setMotorTargetPosition( + motorChannel: number, + targetPosition_counts: number, + targetTolerance_counts: number, + ): Promise { + throw new Error("not implemented"); + } + + setMotorTargetVelocity(motorChannel: number, velocity_cps: number): Promise { + throw new Error("not implemented"); + } + + setNewModuleAddress(newModuleAddress: number): Promise { + throw new Error("not implemented"); + } + + setPhoneChargeControl(chargeEnable: boolean): Promise { + throw new Error("not implemented"); + } + + setServoConfiguration(servoChannel: number, framePeriod: number): Promise { + throw new Error("not implemented"); + } + + setServoEnable(servoChannel: number, enable: boolean): Promise { + throw new Error("not implemented"); + } + + setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise { + throw new Error("not implemented"); + } + + writeI2CMultipleBytes( + i2cChannel: number, + slaveAddress: number, + bytes: number[], + ): Promise { + throw new Error("not implemented"); + } + + writeI2CReadMultipleBytes( + i2cChannel: number, + slaveAddress: number, + numBytesToRead: number, + startAddress: number, + ): Promise { + throw new Error("not implemented"); + } + + writeI2CSingleByte( + i2cChannel: number, + slaveAddress: number, + byte: number, + ): Promise { + throw new Error("not implemented"); + } + + async sendCommand(type: string, params: P): Promise { + let key = 0; + let messagePayload = { + key: key, + commandPayload: JSON.stringify(params), + }; + let payload = { + namespace: "ManualControl", + type: type, + payload: JSON.stringify(messagePayload), + }; + this.webSocketConnection?.send(JSON.stringify(payload)); + + return new Promise((resolve, reject) => { + this.currentActiveCommands.set(key, (response, error) => { + if (response !== undefined) { + resolve(response); + } else { + let e = new Error(); + Object.assign(e, error); + reject(e); + } + }); + }); + } } diff --git a/packages/control-hub/tsconfig.json b/packages/control-hub/tsconfig.json index 4a3682c7..11324309 100644 --- a/packages/control-hub/tsconfig.json +++ b/packages/control-hub/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "esModuleInterop": true, "outDir": "./dist", "rootDir": "./src", "target": "es2017" diff --git a/packages/sample/package.json b/packages/sample/package.json index 7583b14e..a2d1d66a 100644 --- a/packages/sample/package.json +++ b/packages/sample/package.json @@ -7,8 +7,12 @@ "type": "module", "dependencies": { "@rev-robotics/expansion-hub": "*", + "ws": "8.13.0", "commander": "^10.0.1" }, + "devDependencies": { + "@types/ws": "^8.5.4" + }, "scripts": { "build": "tsc", "list": "node dist/main.js list", diff --git a/packages/sample/src/command/list.ts b/packages/sample/src/command/list.ts index a4e9d3b6..8c8c39be 100644 --- a/packages/sample/src/command/list.ts +++ b/packages/sample/src/command/list.ts @@ -1,8 +1,14 @@ import { ExpansionHub, openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; import { hubHierarchyToString } from "../HubStringify.js"; +import { openConnectedControlHub } from "@rev-robotics/control-hub"; export async function list() { - console.log("Starting to search Serial Ports"); + const controlHub = await openConnectedControlHub(); + if (controlHub) { + console.log(`Control Hub: ${controlHub.moduleAddress}\n\n`); + } + + console.log("USB Expansion Hub:"); const hubs: ExpansionHub[] = await openConnectedExpansionHubs(); for (const hub of hubs) { hub.on("error", (e: any) => { @@ -11,10 +17,7 @@ export async function list() { }); console.log(hubHierarchyToString(hub)); } - - setTimeout(() => { - hubs.forEach(async (hub) => { - hub.close(); - }); - }, 2000); + hubs.forEach((hub) => { + hub.close(); + }); } From f03cad706aa6aea84db75fdde8e1508d0a59e896 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 16:39:22 -0500 Subject: [PATCH 005/148] Check version of RC app --- package-lock.json | 38 ++++++++++++------- packages/control-hub/package.json | 4 +- .../control-hub/src/internal/ControlHub.ts | 9 +++-- packages/sample/src/command/list.ts | 1 + 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9ddc925d..3137edcf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2373,6 +2373,12 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, "node_modules/@types/ws": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", @@ -7500,10 +7506,9 @@ "link": true }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -7518,7 +7523,6 @@ "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" }, @@ -8458,8 +8462,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { "version": "1.10.2", @@ -8504,10 +8507,12 @@ "@rev-robotics/rhsplib": "*", "axios": "^1.4.0", "isomorphic-ws": "^5.0.0", + "semver": "^7.5.1", "serialport": "^10.5.0" }, "devDependencies": { "@types/node": "^16.18.18", + "@types/semver": "^7.5.0", "typescript": "^5.0.2" } }, @@ -10176,8 +10181,10 @@ "requires": { "@rev-robotics/rhsplib": "*", "@types/node": "^16.18.18", + "@types/semver": "^7.5.0", "axios": "^1.4.0", "isomorphic-ws": "^5.0.0", + "semver": "^7.5.1", "serialport": "^10.5.0", "typescript": "^5.0.2" } @@ -10333,6 +10340,12 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, "@types/ws": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", @@ -14246,10 +14259,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "requires": { "lru-cache": "^6.0.0" }, @@ -14258,7 +14270,6 @@ "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" } @@ -14993,8 +15004,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yaml": { "version": "1.10.2", diff --git a/packages/control-hub/package.json b/packages/control-hub/package.json index fedd1e66..0a275526 100644 --- a/packages/control-hub/package.json +++ b/packages/control-hub/package.json @@ -6,11 +6,13 @@ "dependencies": { "serialport": "^10.5.0", "isomorphic-ws": "^5.0.0", - "axios":"^1.4.0", + "axios": "^1.4.0", + "semver": "^7.5.1", "@rev-robotics/rhsplib": "*" }, "devDependencies": { "@types/node": "^16.18.18", + "@types/semver": "^7.5.0", "typescript": "^5.0.2" }, "scripts": { diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 0da915ae..2f4c0365 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -16,6 +16,7 @@ import { Version, } from "@rev-robotics/rhsplib"; import axios from "axios"; +import semver from "semver"; import WebSocket from "isomorphic-ws"; export class ControlHub implements ExpansionHub { @@ -66,8 +67,8 @@ export class ControlHub implements ExpansionHub { timeout: 1000, }); if (response.data) { - return true; - //return response.data.webSocketApiVersion === "1"; + let rcVersion: string = response.data.rcVersion; + return semver.gt(rcVersion, semver.coerce("8.1")!.version); } return false; @@ -77,7 +78,9 @@ export class ControlHub implements ExpansionHub { } } - close(): void {} + close(): void { + this.webSocketConnection.close(); + } getADC(): Promise { return Promise.resolve(0); diff --git a/packages/sample/src/command/list.ts b/packages/sample/src/command/list.ts index 8c8c39be..e2a1dd78 100644 --- a/packages/sample/src/command/list.ts +++ b/packages/sample/src/command/list.ts @@ -6,6 +6,7 @@ export async function list() { const controlHub = await openConnectedControlHub(); if (controlHub) { console.log(`Control Hub: ${controlHub.moduleAddress}\n\n`); + controlHub.close(); } console.log("USB Expansion Hub:"); From eaa0ce66f2e991bbdd5ad3acb0824afedc8d2b51 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 16:39:43 -0500 Subject: [PATCH 006/148] Bump required RC version --- packages/control-hub/src/internal/ControlHub.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 2f4c0365..dc244ba0 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -68,7 +68,7 @@ export class ControlHub implements ExpansionHub { }); if (response.data) { let rcVersion: string = response.data.rcVersion; - return semver.gt(rcVersion, semver.coerce("8.1")!.version); + return semver.gt(rcVersion, semver.coerce("8.2")!.version); } return false; From 3d48a61975cdbd316ce1f2772300b445d4c6e267 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 16:43:11 -0500 Subject: [PATCH 007/148] Change how semver requirement is declated --- packages/control-hub/src/internal/ControlHub.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index dc244ba0..722349de 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -68,7 +68,7 @@ export class ControlHub implements ExpansionHub { }); if (response.data) { let rcVersion: string = response.data.rcVersion; - return semver.gt(rcVersion, semver.coerce("8.2")!.version); + return semver.satisfies(rcVersion, ">=8.2"); } return false; From 5ce6863c5a783b7b5fc598b1496ffd4dd270d007 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 16:51:30 -0500 Subject: [PATCH 008/148] Remove error output if no WiFi hub connected --- packages/control-hub/src/discovery.ts | 28 ++++++++----------- .../control-hub/src/internal/ControlHub.ts | 1 - 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index 53ce4169..c04ec4a4 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -1,25 +1,21 @@ import { ControlHub } from "./internal/ControlHub"; -export async function openConnectedControlHub(): Promise< - ControlHub | undefined -> { - try { - return await createControlHub(); - } catch (e: any) { - console.log(e); - return undefined; - } +export async function openConnectedControlHub(): Promise { + try { + return await createControlHub(); + } catch (e: any) { + return undefined; + } } async function createControlHub(): Promise { - let hub = new ControlHub(); + let hub = new ControlHub(); - if(!await hub.isConnected()) { - console.log("Hub not connected") - throw new Error("Hub is not connected via WiFi"); - } + if (!(await hub.isConnected())) { + throw new Error("Hub is not connected via WiFi"); + } - await hub.open(); + await hub.open(); - return hub; + return hub; } diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 722349de..d218eb4a 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -73,7 +73,6 @@ export class ControlHub implements ExpansionHub { return false; } catch (e) { - console.log(e); return false; } } From c0cb9a445e80bbc798befbfca889fd686fa0b8ee Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 26 May 2023 14:47:26 -0500 Subject: [PATCH 009/148] Detect USB control hubs --- package-lock.json | 290 +++++++++++++++++- packages/control-hub/package.json | 4 + packages/control-hub/src/discovery.ts | 73 ++++- packages/control-hub/src/index.ts | 2 +- .../control-hub/src/internal/ControlHub.ts | 16 +- packages/expansion-hub/src/RevHubType.ts | 4 +- packages/sample/package.json | 8 +- packages/sample/src/command/list.ts | 10 +- 8 files changed, 386 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1a56878a..5977c884 100644 --- a/package-lock.json +++ b/package-lock.json @@ -102,6 +102,12 @@ "node": ">=4" } }, + "node_modules/@devicefarmer/minicap-prebuilt": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@devicefarmer/minicap-prebuilt/-/minicap-prebuilt-2.7.1.tgz", + "integrity": "sha512-XM+mPIA9hgwSF4eOq0RnKSXycj2rLNm3Xsl7MM0kG3CtTpX3/J0AA8P+v8zWiGNCMxyhl2VwY52nmQE/QwN3zg==", + "optional": true + }, "node_modules/@gar/promisify": { "version": "1.1.3", "dev": true, @@ -1779,6 +1785,60 @@ "dev": true, "license": "MIT" }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "node_modules/@rev-robotics/control-hub": { "resolved": "packages/control-hub", "link": true @@ -1953,6 +2013,20 @@ "node": ">= 10" } }, + "node_modules/@types/debug": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", + "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", + "dev": true, + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, "node_modules/@types/minimatch": { "version": "3.0.5", "dev": true, @@ -1963,11 +2037,25 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", + "dev": true + }, "node_modules/@types/node": { "version": "16.18.25", - "dev": true, "license": "MIT" }, + "node_modules/@types/node-forge": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.2.tgz", + "integrity": "sha512-TzX3ahoi9xbmaoT58smrBu7oa6dQXb/+PTNCslZyD/55tlJ/osofIMClzZsoo6buDFrg7e4DvVGkZqVgv6OLxw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", "dev": true, @@ -1980,19 +2068,96 @@ }, "node_modules/@types/semver": { "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/ws": { "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, + "node_modules/@u4/adbkit": { + "version": "4.1.19", + "resolved": "https://registry.npmjs.org/@u4/adbkit/-/adbkit-4.1.19.tgz", + "integrity": "sha512-NoPuiYKiv+wTS1qvfZ+GEJXUd4poxJQORLnncoPSi99+hxU0T/xSnv3V3MdFc45IS3IhSxN6eU0AVRP8xvgq+g==", + "dependencies": { + "@u4/adbkit-logcat": "2.1.2", + "@u4/adbkit-monkey": "^1.0.5", + "@u4/minicap-prebuilt": "^1.0.0", + "@xmldom/xmldom": "^0.8.7", + "commander": "9.4.1", + "debug": "~4.3.4", + "get-port": "5.1.1", + "node-forge": "^1.3.1", + "promise-duplex": "^6.0.0", + "promise-readable": "^6.0.0", + "protobufjs": "^6.11.3", + "xpath": "^0.0.32" + }, + "bin": { + "adbkit": "bin/adbkit" + }, + "engines": { + "node": ">= 12.20.0" + }, + "funding": { + "url": "https://github.com/sponsors/urielch" + }, + "optionalDependencies": { + "@devicefarmer/minicap-prebuilt": "^2.7.1" + } + }, + "node_modules/@u4/adbkit-logcat": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@u4/adbkit-logcat/-/adbkit-logcat-2.1.2.tgz", + "integrity": "sha512-mCAuqwWCA2MXYP8nfPJe9IJQ/aTkiFCVvF+qnsBXQ5ceaQOnw2JKNQxjz5Gw7dhYZ9iazvcxg6FNhyec5pfHeQ==", + "engines": { + "node": ">= 12.20.0" + } + }, + "node_modules/@u4/adbkit-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@u4/adbkit-monkey/-/adbkit-monkey-1.0.5.tgz", + "integrity": "sha512-6Hoz8EeKVK3eEJAGR44yzclADhA/5Q4KDlTtegMY4Dl5VMGq+tm1HtrmBvT++kftfrG64/H7xnrOwQ7DwQ2TlA==", + "engines": { + "node": ">= 12.20.0" + } + }, + "node_modules/@u4/adbkit/node_modules/commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/@u4/adbkit/node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@u4/minicap-prebuilt": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@u4/minicap-prebuilt/-/minicap-prebuilt-1.0.0.tgz", + "integrity": "sha512-z+hfnXEZmlCjNUfk4EioIWOLGoMg44a63FWcLqym2xSJuGP9WGS3qJ6ZXjT6ErYsuzSLPR0LGzCqfhXkQs/NBA==" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.7.tgz", + "integrity": "sha512-sI1Ly2cODlWStkINzqGrZ8K6n+MTSbAeQnAipGyL+KZCXuHaRlj2gyyy8B/9MvsFFqN7XHryQnB2QwhzvJXovg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "dev": true, @@ -2761,6 +2926,16 @@ "node": ">=10" } }, + "node_modules/core-js": { + "version": "3.30.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.30.2.tgz", + "integrity": "sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "dev": true, @@ -3399,6 +3574,17 @@ "xtend": "~4.0.1" } }, + "node_modules/get-port": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-6.1.2.tgz", + "integrity": "sha512-BrGGraKm2uPqurfGVj/z97/zv8dPleC6x9JBNRTrDNtCkkRF4rPwrQXFgL7+I+q8QSdU4ntLQX2D7KIxSy8nGw==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "6.0.1", "dev": true, @@ -4115,8 +4301,7 @@ }, "node_modules/isomorphic-ws": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", - "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "license": "MIT", "peerDependencies": { "ws": "*" } @@ -4670,6 +4855,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "node_modules/lru-cache": { "version": "7.18.3", "dev": true, @@ -5191,6 +5381,14 @@ } } }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, "node_modules/node-gyp": { "version": "9.3.1", "dev": true, @@ -6197,11 +6395,35 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/promise-duplex": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/promise-duplex/-/promise-duplex-6.0.0.tgz", + "integrity": "sha512-ZL7rquzjTFzInDBeWYcsT+qddolNvzigahk6MI6qLSbQvlyRRCJkU3JztgaVunzvkH28smRa2Qu/cY9RXtSkgA==", + "dependencies": { + "core-js": "^3.6.5", + "promise-readable": "^6.0.0", + "promise-writable": "^6.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/promise-inflight": { "version": "1.0.1", "dev": true, "license": "ISC" }, + "node_modules/promise-readable": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/promise-readable/-/promise-readable-6.0.0.tgz", + "integrity": "sha512-5NxtmUswijvX5cAM0zPSy6yiCXH/eKBpiiBq6JfAUrmngMquMbzcBhF2qA+ocs4rYYKdvAfv3cOvZxADLtL1CA==", + "dependencies": { + "core-js": "^3.6.5" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/promise-retry": { "version": "2.0.1", "dev": true, @@ -6214,6 +6436,14 @@ "node": ">=10" } }, + "node_modules/promise-writable": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/promise-writable/-/promise-writable-6.0.0.tgz", + "integrity": "sha512-b81zre/itgJFS7dwWzIdKNVVqvLiUxYRS/wolUB0H1YY/tAaS146XGKa4Q/5wCbsnXLyn0MCeV6f8HHe4iUHLg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/promzard": { "version": "0.3.0", "dev": true, @@ -6227,6 +6457,31 @@ "dev": true, "license": "ISC" }, + "node_modules/protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, "node_modules/protocols": { "version": "2.0.1", "dev": true, @@ -7499,8 +7754,7 @@ }, "node_modules/ws": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -7517,6 +7771,14 @@ } } }, + "node_modules/xpath": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz", + "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==", + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "dev": true, @@ -7584,6 +7846,10 @@ "@types/node": "^16.18.18", "@types/semver": "^7.5.0", "typescript": "^5.0.2" + }, + "peerDependencies": { + "@u4/adbkit": ">= 4.1.19", + "get-port": "^6.1.2" } }, "packages/expansion-hub": { @@ -7618,10 +7884,14 @@ "version": "0.1.0", "dependencies": { "@rev-robotics/expansion-hub": "*", + "@u4/adbkit": "^4.1.19", "commander": "^10.0.1", + "get-port": "^6.1.2", "ws": "8.13.0" }, "devDependencies": { + "@types/debug": "^4.1.8", + "@types/node-forge": "^1.3.2", "@types/ws": "^8.5.4" } } diff --git a/packages/control-hub/package.json b/packages/control-hub/package.json index 53b2bbe6..b658abc7 100644 --- a/packages/control-hub/package.json +++ b/packages/control-hub/package.json @@ -11,6 +11,10 @@ "semver": "^7.5.1", "@rev-robotics/rhsplib": "*" }, + "peerDependencies": { + "@u4/adbkit": ">= 4.1.19", + "get-port": "^6.1.2" + }, "devDependencies": { "@types/node": "^16.18.18", "@types/semver": "^7.5.0", diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index b9e13051..97ad1876 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -1,17 +1,62 @@ import { ControlHub } from "./internal/ControlHub.js"; +import { Adb, DeviceClient } from "@u4/adbkit"; +import getPort from "get-port"; export async function openConnectedControlHub(): Promise { try { - return await createControlHub(); + return await createWiFiControlHub(); } catch (e: any) { return undefined; } } -async function createControlHub(): Promise { +export async function openUsbControlHubs(): Promise { + let adbClient = Adb.createClient(); + + let devices = await adbClient.listDevices(); + let controlHubs = devices.filter(async (device) => { + let deviceClient = device.getClient(); + let isHub = await isControlHub(deviceClient); + console.log(`Is hub? ${isHub}`); + if (isHub) { + console.log("configuring tcp"); + await configureHubTcp(deviceClient); + } + return isHub; + }); + + console.log(`Found ${controlHubs.length} Control hubs`); + + let result: ControlHub[] = []; + + for (const device of controlHubs) { + let hub = new ControlHub(); + console.log("Opening hub"); + await hub.open(); + result.push(hub); + } + return result; +} + +async function configureHubTcp(deviceClient: DeviceClient) { + let port = await findAdjacentPorts(); + console.log(`Found port ${port}`); + await deviceClient.forward(`tcp:${port}`, `tcp:8080`); + await deviceClient.forward(`tcp:${port + 1}`, `tcp:8081`); +} + +async function isControlHub(deviceClient: DeviceClient): Promise { + let serialasusb = await deviceClient.execOut( + "getprop persist.ftcandroid.serialasusb", + "utf8", + ); + return serialasusb.startsWith("true"); +} + +async function createWiFiControlHub(): Promise { let hub = new ControlHub(); - if (!(await hub.isConnected())) { + if (!(await hub.isWiFiConnected())) { throw new Error("Hub is not connected via WiFi"); } @@ -19,3 +64,25 @@ async function createControlHub(): Promise { return hub; } + +/** + * Returns the first of two adjacent ports. + * @param host + */ +export async function findAdjacentPorts(host: string = "127.0.0.1"): Promise { + console.log("Finding ports"); + try { + //const getPort = (await import("get-port")).default; + let port = await getPort({ host: host }); + let adjacent = await getPort({ host: host, port: port + 1 }); + console.log("Tried to get ports"); + if (adjacent === port + 1) return port; + else { + return await findAdjacentPorts(host); + } + } catch (e) { + console.log("Got error checking ports"); + console.log(e); + throw e; + } +} diff --git a/packages/control-hub/src/index.ts b/packages/control-hub/src/index.ts index 540ec035..e5d4c645 100644 --- a/packages/control-hub/src/index.ts +++ b/packages/control-hub/src/index.ts @@ -1 +1 @@ -export * from "./discovery.js"; +export { openConnectedControlHub, openUsbControlHubs } from "./discovery.js"; diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 18353a6a..f3402705 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -22,6 +22,7 @@ import { import axios from "axios"; import semver from "semver"; import WebSocket from "isomorphic-ws"; +import adb from "@u4/adbkit"; export class ControlHub implements ExpansionHub { readonly isOpen: boolean = true; @@ -65,7 +66,7 @@ export class ControlHub implements ExpansionHub { }); } - async isConnected(): Promise { + async isWiFiConnected(): Promise { try { let response = await axios.get("http://192.168.43.1:8080/js/rcInfo.json", { timeout: 1000, @@ -81,6 +82,19 @@ export class ControlHub implements ExpansionHub { } } + async isUsbConnected(): Promise { + let adbClient = adb.createClient(); + let devices = await adbClient.listDevicesWithPaths(); + let controlHubs = devices.filter((device) => { + return this.isControlHub(device.path); + }); + return false; + } + + private isControlHub(path: string): boolean { + return path.includes("_box") && path.includes("msm8916_64"); + } + close(): void { this.webSocketConnection.close(); } diff --git a/packages/expansion-hub/src/RevHubType.ts b/packages/expansion-hub/src/RevHubType.ts index b40e5d0f..de4220b4 100644 --- a/packages/expansion-hub/src/RevHubType.ts +++ b/packages/expansion-hub/src/RevHubType.ts @@ -1,4 +1,4 @@ export enum RevHubType { - ExpansionHub, - ControlHub, + ExpansionHub, + ControlHub, } diff --git a/packages/sample/package.json b/packages/sample/package.json index a2d1d66a..169c79d3 100644 --- a/packages/sample/package.json +++ b/packages/sample/package.json @@ -8,10 +8,14 @@ "dependencies": { "@rev-robotics/expansion-hub": "*", "ws": "8.13.0", - "commander": "^10.0.1" + "commander": "^10.0.1", + "@u4/adbkit": "^4.1.19", + "get-port": "^6.1.2" }, "devDependencies": { - "@types/ws": "^8.5.4" + "@types/ws": "^8.5.4", + "@types/node-forge": "^1.3.2", + "@types/debug": "^4.1.8" }, "scripts": { "build": "tsc", diff --git a/packages/sample/src/command/list.ts b/packages/sample/src/command/list.ts index e2a1dd78..1e8b0df1 100644 --- a/packages/sample/src/command/list.ts +++ b/packages/sample/src/command/list.ts @@ -1,11 +1,17 @@ import { ExpansionHub, openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; import { hubHierarchyToString } from "../HubStringify.js"; -import { openConnectedControlHub } from "@rev-robotics/control-hub"; +import { openConnectedControlHub, openUsbControlHubs } from "@rev-robotics/control-hub"; export async function list() { + let usbControlHubs = await openUsbControlHubs(); + for (const hub of usbControlHubs) { + console.log(`USB Control Hub: ${hub.moduleAddress}\n\n`); + hub.close(); + } + const controlHub = await openConnectedControlHub(); if (controlHub) { - console.log(`Control Hub: ${controlHub.moduleAddress}\n\n`); + console.log(`WiFi Control Hub: ${controlHub.moduleAddress}\n\n`); controlHub.close(); } From ce97332e46833222aa65995dfadc62b5722274da Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 26 May 2023 16:55:21 -0500 Subject: [PATCH 010/148] Fix connection to USB expansion hubs --- packages/control-hub/src/discovery.ts | 33 +++++++------------ .../control-hub/src/internal/ControlHub.ts | 13 ++------ packages/sample/src/HubStringify.ts | 4 +-- packages/sample/src/command/list.ts | 1 - 4 files changed, 16 insertions(+), 35 deletions(-) diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index 97ad1876..788f0b9d 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -12,37 +12,30 @@ export async function openConnectedControlHub(): Promise export async function openUsbControlHubs(): Promise { let adbClient = Adb.createClient(); + let controlHubs: ControlHub[] = []; let devices = await adbClient.listDevices(); - let controlHubs = devices.filter(async (device) => { + for (const device of devices) { let deviceClient = device.getClient(); let isHub = await isControlHub(deviceClient); - console.log(`Is hub? ${isHub}`); if (isHub) { - console.log("configuring tcp"); - await configureHubTcp(deviceClient); - } - return isHub; - }); - - console.log(`Found ${controlHubs.length} Control hubs`); - - let result: ControlHub[] = []; + let port = await configureHubTcp(deviceClient); - for (const device of controlHubs) { - let hub = new ControlHub(); - console.log("Opening hub"); - await hub.open(); - result.push(hub); + let hub = new ControlHub(); + await hub.open("127.0.0.1", (port + 1).toString()); + controlHubs.push(hub); + } } - return result; + + return controlHubs; } -async function configureHubTcp(deviceClient: DeviceClient) { +async function configureHubTcp(deviceClient: DeviceClient): Promise { let port = await findAdjacentPorts(); - console.log(`Found port ${port}`); await deviceClient.forward(`tcp:${port}`, `tcp:8080`); await deviceClient.forward(`tcp:${port + 1}`, `tcp:8081`); + + return port; } async function isControlHub(deviceClient: DeviceClient): Promise { @@ -70,12 +63,10 @@ async function createWiFiControlHub(): Promise { * @param host */ export async function findAdjacentPorts(host: string = "127.0.0.1"): Promise { - console.log("Finding ports"); try { //const getPort = (await import("get-port")).default; let port = await getPort({ host: host }); let adjacent = await getPort({ host: host, port: port + 1 }); - console.log("Tried to get ports"); if (adjacent === port + 1) return port; else { return await findAdjacentPorts(host); diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index f3402705..e7cb9fc6 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -37,8 +37,8 @@ export class ControlHub implements ExpansionHub { (response: any | undefined, error: any | undefined) => void >(); - async open(): Promise { - this.webSocketConnection = new WebSocket("ws://192.168.43.1:8081"); + async open(ip: string = "192.168.43.1", port: string = "8081"): Promise { + this.webSocketConnection = new WebSocket(`ws://${ip}:${port}`); this.webSocketConnection.on("message", (data) => { let rawMessage = JSON.parse(data.toString()); @@ -82,15 +82,6 @@ export class ControlHub implements ExpansionHub { } } - async isUsbConnected(): Promise { - let adbClient = adb.createClient(); - let devices = await adbClient.listDevicesWithPaths(); - let controlHubs = devices.filter((device) => { - return this.isControlHub(device.path); - }); - return false; - } - private isControlHub(path: string): boolean { return path.includes("_box") && path.includes("msm8916_64"); } diff --git a/packages/sample/src/HubStringify.ts b/packages/sample/src/HubStringify.ts index 71a67534..e36292b2 100644 --- a/packages/sample/src/HubStringify.ts +++ b/packages/sample/src/HubStringify.ts @@ -1,7 +1,7 @@ import { RevHub } from "@rev-robotics/expansion-hub"; export function hubHierarchyToString(hub: RevHub): string { - let result = `RevHub: ${hub.moduleAddress}\n`; + let result = `USB Expansion Hub: ${hub.moduleAddress}\n`; if (hub.isExpansionHub()) { console.log(`Is open? ${hub.isOpen}`); @@ -9,7 +9,7 @@ export function hubHierarchyToString(hub: RevHub): string { if (hub.isParent()) { for (const child of hub.children) { - result += `\tRevHub: ${child.moduleAddress}\n`; + result += `\tUSB Expansion Hub: ${child.moduleAddress}\n`; } } diff --git a/packages/sample/src/command/list.ts b/packages/sample/src/command/list.ts index 1e8b0df1..41636f50 100644 --- a/packages/sample/src/command/list.ts +++ b/packages/sample/src/command/list.ts @@ -15,7 +15,6 @@ export async function list() { controlHub.close(); } - console.log("USB Expansion Hub:"); const hubs: ExpansionHub[] = await openConnectedExpansionHubs(); for (const hub of hubs) { hub.on("error", (e: any) => { From b4de2a4ee931e21b9fc421dfffa9d9df1e111ea8 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 09:26:37 -0500 Subject: [PATCH 011/148] Add explicit dependency on control-hub --- package-lock.json | 1 + packages/sample/package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/package-lock.json b/package-lock.json index 5977c884..0bfadda8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7883,6 +7883,7 @@ "packages/sample": { "version": "0.1.0", "dependencies": { + "@rev-robotics/control-hub": "*", "@rev-robotics/expansion-hub": "*", "@u4/adbkit": "^4.1.19", "commander": "^10.0.1", diff --git a/packages/sample/package.json b/packages/sample/package.json index 169c79d3..d513e8c9 100644 --- a/packages/sample/package.json +++ b/packages/sample/package.json @@ -6,6 +6,7 @@ "private": true, "type": "module", "dependencies": { + "@rev-robotics/control-hub": "*", "@rev-robotics/expansion-hub": "*", "ws": "8.13.0", "commander": "^10.0.1", From 5ad4ef3900a2872d04caa6724c2bf0a182556e87 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 09:49:01 -0500 Subject: [PATCH 012/148] Restructure Control Hub module to export interface and implement with internal class --- packages/control-hub/src/ControlHub.ts | 7 +++++++ packages/control-hub/src/discovery.ts | 8 +++++--- packages/control-hub/src/index.ts | 1 + packages/control-hub/src/internal/ControlHub.ts | 16 +++++++++++----- packages/sample/src/command/list.ts | 6 +++++- 5 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 packages/control-hub/src/ControlHub.ts diff --git a/packages/control-hub/src/ControlHub.ts b/packages/control-hub/src/ControlHub.ts new file mode 100644 index 00000000..01e28c1e --- /dev/null +++ b/packages/control-hub/src/ControlHub.ts @@ -0,0 +1,7 @@ +import { ExpansionHub, ParentRevHub } from "@rev-robotics/expansion-hub"; + +export interface ParentControlHub extends ParentRevHub, ControlHub { + readonly serialNumber: string; +} + +export interface ControlHub extends ExpansionHub {} diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index 788f0b9d..4da839de 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -1,6 +1,7 @@ -import { ControlHub } from "./internal/ControlHub.js"; +import { ControlHubInternal } from "./internal/ControlHub.js"; import { Adb, DeviceClient } from "@u4/adbkit"; import getPort from "get-port"; +import { ControlHub } from "./ControlHub.js"; export async function openConnectedControlHub(): Promise { try { @@ -20,8 +21,9 @@ export async function openUsbControlHubs(): Promise { let isHub = await isControlHub(deviceClient); if (isHub) { let port = await configureHubTcp(deviceClient); + let serialNumber = device.id; - let hub = new ControlHub(); + let hub = new ControlHubInternal(serialNumber); await hub.open("127.0.0.1", (port + 1).toString()); controlHubs.push(hub); } @@ -47,7 +49,7 @@ async function isControlHub(deviceClient: DeviceClient): Promise { } async function createWiFiControlHub(): Promise { - let hub = new ControlHub(); + let hub = new ControlHubInternal(); if (!(await hub.isWiFiConnected())) { throw new Error("Hub is not connected via WiFi"); diff --git a/packages/control-hub/src/index.ts b/packages/control-hub/src/index.ts index e5d4c645..98860739 100644 --- a/packages/control-hub/src/index.ts +++ b/packages/control-hub/src/index.ts @@ -1 +1,2 @@ export { openConnectedControlHub, openUsbControlHubs } from "./discovery.js"; +export * from "./ControlHub.js"; diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index e7cb9fc6..7d0370dc 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -23,13 +23,15 @@ import axios from "axios"; import semver from "semver"; import WebSocket from "isomorphic-ws"; import adb from "@u4/adbkit"; +import { ControlHub, ParentControlHub } from "../ControlHub.js"; -export class ControlHub implements ExpansionHub { +export class ControlHubInternal implements ControlHub { readonly isOpen: boolean = true; moduleAddress: number = 0; responseTimeoutMs: number = 0; type: RevHubType = RevHubType.ControlHub; webSocketConnection!: WebSocket; + private readonly serialNumber?: string; keyGenerator = 0; currentActiveCommands = new Map< @@ -37,6 +39,14 @@ export class ControlHub implements ExpansionHub { (response: any | undefined, error: any | undefined) => void >(); + constructor(serialNumber?: string) { + this.serialNumber = serialNumber; + } + + isParent(): this is ParentControlHub { + return this.serialNumber !== undefined; + } + async open(ip: string = "192.168.43.1", port: string = "8081"): Promise { this.webSocketConnection = new WebSocket(`ws://${ip}:${port}`); @@ -209,10 +219,6 @@ export class ControlHub implements ExpansionHub { throw new Error("not implemented"); } - isParent(): this is ParentRevHub { - throw new Error("not implemented"); - } - on(eventName: "error", listener: (error: Error) => void): RevHub { throw new Error("not implemented"); } diff --git a/packages/sample/src/command/list.ts b/packages/sample/src/command/list.ts index 41636f50..f4d61df6 100644 --- a/packages/sample/src/command/list.ts +++ b/packages/sample/src/command/list.ts @@ -5,7 +5,11 @@ import { openConnectedControlHub, openUsbControlHubs } from "@rev-robotics/contr export async function list() { let usbControlHubs = await openUsbControlHubs(); for (const hub of usbControlHubs) { - console.log(`USB Control Hub: ${hub.moduleAddress}\n\n`); + if (hub.isParent()) { + console.log(`USB Control Hub: ${hub.serialNumber} ${hub.moduleAddress}\n\n`); + } else { + console.log(`\tUSB Control Hub: ${hub.moduleAddress}\n\n`); + } hub.close(); } From 41ae6a35732081f014d88772520778e6bf399f33 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 09:50:45 -0500 Subject: [PATCH 013/148] Show serial number for parent expansion hub --- packages/sample/src/HubStringify.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/sample/src/HubStringify.ts b/packages/sample/src/HubStringify.ts index e36292b2..63976eab 100644 --- a/packages/sample/src/HubStringify.ts +++ b/packages/sample/src/HubStringify.ts @@ -1,13 +1,10 @@ import { RevHub } from "@rev-robotics/expansion-hub"; export function hubHierarchyToString(hub: RevHub): string { - let result = `USB Expansion Hub: ${hub.moduleAddress}\n`; - - if (hub.isExpansionHub()) { - console.log(`Is open? ${hub.isOpen}`); - } + let result = ""; if (hub.isParent()) { + result = `USB Expansion Hub: ${hub.serialNumber} ${hub.moduleAddress}\n`; for (const child of hub.children) { result += `\tUSB Expansion Hub: ${child.moduleAddress}\n`; } From 27ffa131ef47f5099929f8ec0b74a64ff6406b58 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 13:07:46 -0500 Subject: [PATCH 014/148] Remove ParentControlHub, since control hubs will always be parents --- package-lock.json | 1 + packages/control-hub/package.json | 1 + packages/control-hub/src/ControlHub.ts | 6 +----- packages/control-hub/src/discovery.ts | 2 +- packages/control-hub/src/internal/ControlHub.ts | 17 +++++++++++++---- packages/sample/src/command/list.ts | 6 +----- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0bfadda8..e7d7b02a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7844,6 +7844,7 @@ }, "devDependencies": { "@types/node": "^16.18.18", + "@types/node-forge": "^1.3.2", "@types/semver": "^7.5.0", "typescript": "^5.0.2" }, diff --git a/packages/control-hub/package.json b/packages/control-hub/package.json index b658abc7..fd6fb719 100644 --- a/packages/control-hub/package.json +++ b/packages/control-hub/package.json @@ -18,6 +18,7 @@ "devDependencies": { "@types/node": "^16.18.18", "@types/semver": "^7.5.0", + "@types/node-forge": "^1.3.2", "typescript": "^5.0.2" }, "scripts": { diff --git a/packages/control-hub/src/ControlHub.ts b/packages/control-hub/src/ControlHub.ts index 01e28c1e..07582e58 100644 --- a/packages/control-hub/src/ControlHub.ts +++ b/packages/control-hub/src/ControlHub.ts @@ -1,7 +1,3 @@ import { ExpansionHub, ParentRevHub } from "@rev-robotics/expansion-hub"; -export interface ParentControlHub extends ParentRevHub, ControlHub { - readonly serialNumber: string; -} - -export interface ControlHub extends ExpansionHub {} +export interface ControlHub extends ExpansionHub, ParentRevHub {} diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index 4da839de..49ba71e6 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -49,7 +49,7 @@ async function isControlHub(deviceClient: DeviceClient): Promise { } async function createWiFiControlHub(): Promise { - let hub = new ControlHubInternal(); + let hub = new ControlHubInternal("Placeholder"); if (!(await hub.isWiFiConnected())) { throw new Error("Hub is not connected via WiFi"); diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 7d0370dc..4646300a 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -23,7 +23,7 @@ import axios from "axios"; import semver from "semver"; import WebSocket from "isomorphic-ws"; import adb from "@u4/adbkit"; -import { ControlHub, ParentControlHub } from "../ControlHub.js"; +import { ControlHub } from "../ControlHub.js"; export class ControlHubInternal implements ControlHub { readonly isOpen: boolean = true; @@ -31,7 +31,8 @@ export class ControlHubInternal implements ControlHub { responseTimeoutMs: number = 0; type: RevHubType = RevHubType.ControlHub; webSocketConnection!: WebSocket; - private readonly serialNumber?: string; + readonly serialNumber: string; + readonly children: ReadonlyArray = []; keyGenerator = 0; currentActiveCommands = new Map< @@ -39,11 +40,11 @@ export class ControlHubInternal implements ControlHub { (response: any | undefined, error: any | undefined) => void >(); - constructor(serialNumber?: string) { + constructor(serialNumber: string) { this.serialNumber = serialNumber; } - isParent(): this is ParentControlHub { + isParent(): this is ParentRevHub { return this.serialNumber !== undefined; } @@ -418,4 +419,12 @@ export class ControlHubInternal implements ControlHub { }); }); } + + addChild(hub: RevHub): void { + throw new Error("not implemented"); + } + + addChildByAddress(moduleAddress: number): Promise { + throw new Error("not implemented"); + } } diff --git a/packages/sample/src/command/list.ts b/packages/sample/src/command/list.ts index f4d61df6..b7622f0a 100644 --- a/packages/sample/src/command/list.ts +++ b/packages/sample/src/command/list.ts @@ -5,11 +5,7 @@ import { openConnectedControlHub, openUsbControlHubs } from "@rev-robotics/contr export async function list() { let usbControlHubs = await openUsbControlHubs(); for (const hub of usbControlHubs) { - if (hub.isParent()) { - console.log(`USB Control Hub: ${hub.serialNumber} ${hub.moduleAddress}\n\n`); - } else { - console.log(`\tUSB Control Hub: ${hub.moduleAddress}\n\n`); - } + console.log(`USB Control Hub: ${hub.serialNumber} ${hub.moduleAddress}\n\n`); hub.close(); } From a3712d3a565170087e6c9fc5a2522a8731d7ba73 Mon Sep 17 00:00:00 2001 From: Landry Norris <37489471+LandryNorris@users.noreply.github.com> Date: Tue, 30 May 2023 13:17:14 -0500 Subject: [PATCH 015/148] Fix wording in package description Co-authored-by: Noah Andrews --- packages/control-hub/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/control-hub/package.json b/packages/control-hub/package.json index fd6fb719..20412dc5 100644 --- a/packages/control-hub/package.json +++ b/packages/control-hub/package.json @@ -1,7 +1,7 @@ { "name": "@rev-robotics/control-hub", "version": "0.1.0", - "description": "High level library for REV control hub", + "description": "High level library for the REV Robotics Control Hub", "main": "dist/index.js", "type": "module", "dependencies": { From a91ee0fce8db294e7b56d5a33c62fcaf0d339918 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 14:18:08 -0500 Subject: [PATCH 016/148] Create core module --- package-lock.json | 21 +++++++++++++++++++ packages/control-hub/package.json | 3 ++- packages/control-hub/src/ControlHub.ts | 3 --- packages/control-hub/src/discovery.ts | 2 +- packages/control-hub/src/index.ts | 1 - .../control-hub/src/internal/ControlHub.ts | 14 ++++++------- packages/core/package.json | 21 +++++++++++++++++++ packages/core/src/ControlHub.ts | 4 ++++ .../src/ExpansionHub.ts | 0 .../{expansion-hub => core}/src/RevHub.ts | 0 .../{expansion-hub => core}/src/RevHubType.ts | 0 packages/core/src/index.ts | 4 ++++ packages/core/tsconfig.json | 9 ++++++++ packages/expansion-hub/package.json | 1 + packages/expansion-hub/src/discovery.ts | 2 +- packages/expansion-hub/src/index.ts | 3 --- .../src/internal/ExpansionHub.ts | 7 +++---- packages/expansion-hub/src/open-rev-hub.ts | 2 +- packages/sample/src/HubStringify.ts | 2 +- packages/sample/src/command/led.ts | 2 +- packages/sample/src/command/list.ts | 3 ++- 21 files changed, 79 insertions(+), 25 deletions(-) delete mode 100644 packages/control-hub/src/ControlHub.ts create mode 100644 packages/core/package.json create mode 100644 packages/core/src/ControlHub.ts rename packages/{expansion-hub => core}/src/ExpansionHub.ts (100%) rename packages/{expansion-hub => core}/src/RevHub.ts (100%) rename packages/{expansion-hub => core}/src/RevHubType.ts (100%) create mode 100644 packages/core/src/index.ts create mode 100644 packages/core/tsconfig.json diff --git a/package-lock.json b/package-lock.json index e7d7b02a..079564c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1847,6 +1847,10 @@ "resolved": "packages/expansion-hub", "link": true }, + "node_modules/@rev-robotics/rev-hub-core": { + "resolved": "packages/core", + "link": true + }, "node_modules/@rev-robotics/rhsplib": { "resolved": "packages/rhsplib", "link": true @@ -7836,6 +7840,7 @@ "name": "@rev-robotics/control-hub", "version": "0.1.0", "dependencies": { + "@rev-robotics/rev-hub-core": "*", "@rev-robotics/rhsplib": "*", "axios": "^1.4.0", "isomorphic-ws": "^5.0.0", @@ -7853,10 +7858,26 @@ "get-port": "^6.1.2" } }, + "packages/core": { + "name": "@rev-robotics/rev-hub-core", + "version": "0.1.0", + "dependencies": { + "@rev-robotics/rhsplib": "*" + }, + "devDependencies": { + "@types/node": "^16.18.18", + "typescript": "^5.0.2" + }, + "peerDependencies": { + "@u4/adbkit": ">= 4.1.19", + "get-port": "^6.1.2" + } + }, "packages/expansion-hub": { "name": "@rev-robotics/expansion-hub", "version": "0.1.0", "dependencies": { + "@rev-robotics/rev-hub-core": "*", "@rev-robotics/rhsplib": "*", "serialport": "^10.5.0" }, diff --git a/packages/control-hub/package.json b/packages/control-hub/package.json index 20412dc5..c5002852 100644 --- a/packages/control-hub/package.json +++ b/packages/control-hub/package.json @@ -9,7 +9,8 @@ "isomorphic-ws": "^5.0.0", "axios": "^1.4.0", "semver": "^7.5.1", - "@rev-robotics/rhsplib": "*" + "@rev-robotics/rhsplib": "*", + "@rev-robotics/rev-hub-core": "*" }, "peerDependencies": { "@u4/adbkit": ">= 4.1.19", diff --git a/packages/control-hub/src/ControlHub.ts b/packages/control-hub/src/ControlHub.ts deleted file mode 100644 index 07582e58..00000000 --- a/packages/control-hub/src/ControlHub.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { ExpansionHub, ParentRevHub } from "@rev-robotics/expansion-hub"; - -export interface ControlHub extends ExpansionHub, ParentRevHub {} diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index 49ba71e6..ef4033c8 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -1,7 +1,7 @@ import { ControlHubInternal } from "./internal/ControlHub.js"; import { Adb, DeviceClient } from "@u4/adbkit"; import getPort from "get-port"; -import { ControlHub } from "./ControlHub.js"; +import { ControlHub } from "@rev-robotics/rev-hub-core"; export async function openConnectedControlHub(): Promise { try { diff --git a/packages/control-hub/src/index.ts b/packages/control-hub/src/index.ts index 98860739..e5d4c645 100644 --- a/packages/control-hub/src/index.ts +++ b/packages/control-hub/src/index.ts @@ -1,2 +1 @@ export { openConnectedControlHub, openUsbControlHubs } from "./discovery.js"; -export * from "./ControlHub.js"; diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 4646300a..f8cf0e16 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -1,9 +1,3 @@ -import { - ExpansionHub, - ParentRevHub, - RevHub, - RevHubType, -} from "@rev-robotics/expansion-hub"; import { BulkInputData, DebugGroup, @@ -23,7 +17,13 @@ import axios from "axios"; import semver from "semver"; import WebSocket from "isomorphic-ws"; import adb from "@u4/adbkit"; -import { ControlHub } from "../ControlHub.js"; +import { + ControlHub, + ExpansionHub, + ParentRevHub, + RevHub, + RevHubType, +} from "@rev-robotics/rev-hub-core"; export class ControlHubInternal implements ControlHub { readonly isOpen: boolean = true; diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 00000000..8796f02b --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,21 @@ +{ + "name": "@rev-robotics/rev-hub-core", + "version": "0.1.0", + "description": "Interfaces for REV Robotics hub devices", + "main": "dist/index.js", + "type": "module", + "dependencies": { + "@rev-robotics/rhsplib": "*" + }, + "peerDependencies": { + "@u4/adbkit": ">= 4.1.19", + "get-port": "^6.1.2" + }, + "devDependencies": { + "@types/node": "^16.18.18", + "typescript": "^5.0.2" + }, + "scripts": { + "build": "tsc" + } +} \ No newline at end of file diff --git a/packages/core/src/ControlHub.ts b/packages/core/src/ControlHub.ts new file mode 100644 index 00000000..01ce2a91 --- /dev/null +++ b/packages/core/src/ControlHub.ts @@ -0,0 +1,4 @@ +import { ExpansionHub } from "./ExpansionHub.js"; +import { ParentRevHub } from "./RevHub.js"; + +export interface ControlHub extends ExpansionHub, ParentRevHub {} diff --git a/packages/expansion-hub/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts similarity index 100% rename from packages/expansion-hub/src/ExpansionHub.ts rename to packages/core/src/ExpansionHub.ts diff --git a/packages/expansion-hub/src/RevHub.ts b/packages/core/src/RevHub.ts similarity index 100% rename from packages/expansion-hub/src/RevHub.ts rename to packages/core/src/RevHub.ts diff --git a/packages/expansion-hub/src/RevHubType.ts b/packages/core/src/RevHubType.ts similarity index 100% rename from packages/expansion-hub/src/RevHubType.ts rename to packages/core/src/RevHubType.ts diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts new file mode 100644 index 00000000..93e8d078 --- /dev/null +++ b/packages/core/src/index.ts @@ -0,0 +1,4 @@ +export * from "./ExpansionHub.js"; +export * from "./ControlHub.js"; +export * from "./RevHub.js"; +export * from "./RevHubType.js"; diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 00000000..11324309 --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "esModuleInterop": true, + "outDir": "./dist", + "rootDir": "./src", + "target": "es2017" + } +} diff --git a/packages/expansion-hub/package.json b/packages/expansion-hub/package.json index 03f81290..4af5912c 100644 --- a/packages/expansion-hub/package.json +++ b/packages/expansion-hub/package.json @@ -6,6 +6,7 @@ "type": "module", "dependencies": { "serialport": "^10.5.0", + "@rev-robotics/rev-hub-core": "*", "@rev-robotics/rhsplib": "*" }, "devDependencies": { diff --git a/packages/expansion-hub/src/discovery.ts b/packages/expansion-hub/src/discovery.ts index 53450913..ed4a1a63 100644 --- a/packages/expansion-hub/src/discovery.ts +++ b/packages/expansion-hub/src/discovery.ts @@ -1,5 +1,5 @@ import { SerialPort } from "serialport"; -import { ExpansionHub } from "./ExpansionHub.js"; +import { ExpansionHub } from "@rev-robotics/rev-hub-core"; import { openExpansionHubAndAllChildren } from "./open-rev-hub.js"; export async function getPossibleExpansionHubSerialNumbers(): Promise { diff --git a/packages/expansion-hub/src/index.ts b/packages/expansion-hub/src/index.ts index 1efe331c..7e91e51a 100644 --- a/packages/expansion-hub/src/index.ts +++ b/packages/expansion-hub/src/index.ts @@ -5,6 +5,3 @@ export { openParentExpansionHub, openExpansionHubAndAllChildren, } from "./open-rev-hub.js"; -export * from "./ExpansionHub.js"; -export * from "./RevHub.js"; -export * from "./RevHubType.js"; diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index 4be92d3c..b0d70876 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -1,4 +1,4 @@ -import { ExpansionHub } from "../ExpansionHub.js"; +import { ExpansionHub, ParentRevHub, RevHub } from "@rev-robotics/rev-hub-core"; import { BulkInputData, DebugGroup, @@ -17,9 +17,8 @@ import { Version, } from "@rev-robotics/rhsplib"; import { closeSerialPort } from "../open-rev-hub.js"; -import { ParentRevHub, RevHub } from "../RevHub.js"; import { EventEmitter } from "events"; -import { RevHubType } from "../RevHubType.js"; +import { RevHubType } from "@rev-robotics/rev-hub-core"; export class ExpansionHubInternal implements ExpansionHub { constructor(isParent: true, serial: SerialPort, serialNumber: string); @@ -44,7 +43,7 @@ export class ExpansionHubInternal implements ExpansionHub { keepAliveTimer?: NodeJS.Timer; - type = RevHubType.ExpansionHub; + type: RevHubType = RevHubType.ExpansionHub; private emitter = new EventEmitter(); isParent(): this is ParentRevHub { diff --git a/packages/expansion-hub/src/open-rev-hub.ts b/packages/expansion-hub/src/open-rev-hub.ts index 65206c12..157260c2 100644 --- a/packages/expansion-hub/src/open-rev-hub.ts +++ b/packages/expansion-hub/src/open-rev-hub.ts @@ -1,4 +1,4 @@ -import { ExpansionHub, ParentExpansionHub } from "./ExpansionHub.js"; +import { ExpansionHub, ParentExpansionHub } from "@rev-robotics/rev-hub-core"; import { SerialParity, SerialFlowControl, diff --git a/packages/sample/src/HubStringify.ts b/packages/sample/src/HubStringify.ts index 63976eab..77d9e5fd 100644 --- a/packages/sample/src/HubStringify.ts +++ b/packages/sample/src/HubStringify.ts @@ -1,4 +1,4 @@ -import { RevHub } from "@rev-robotics/expansion-hub"; +import { RevHub } from "@rev-robotics/rev-hub-core"; export function hubHierarchyToString(hub: RevHub): string { let result = ""; diff --git a/packages/sample/src/command/led.ts b/packages/sample/src/command/led.ts index e6571753..0e588969 100644 --- a/packages/sample/src/command/led.ts +++ b/packages/sample/src/command/led.ts @@ -1,9 +1,9 @@ import { createLedPattern, - ExpansionHub, LedPatternStep, openConnectedExpansionHubs, } from "@rev-robotics/expansion-hub"; +import { ExpansionHub } from "@rev-robotics/rev-hub-core"; export async function led() { const hubs: ExpansionHub[] = await openConnectedExpansionHubs(); diff --git a/packages/sample/src/command/list.ts b/packages/sample/src/command/list.ts index b7622f0a..bb864f94 100644 --- a/packages/sample/src/command/list.ts +++ b/packages/sample/src/command/list.ts @@ -1,6 +1,7 @@ -import { ExpansionHub, openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; +import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; import { hubHierarchyToString } from "../HubStringify.js"; import { openConnectedControlHub, openUsbControlHubs } from "@rev-robotics/control-hub"; +import { ExpansionHub } from "@rev-robotics/rev-hub-core"; export async function list() { let usbControlHubs = await openUsbControlHubs(); From e8116eadaa9253c32e533ab76f93572b8c1fcfc3 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 15:13:57 -0500 Subject: [PATCH 017/148] Move adbkit usage out of control hub module --- package-lock.json | 7 +-- packages/control-hub/package.json | 4 -- packages/control-hub/src/discovery.ts | 59 ------------------ packages/control-hub/src/index.ts | 2 +- .../control-hub/src/internal/ControlHub.ts | 1 - packages/expansion-hub/package.json | 3 +- packages/sample/src/adb-setup.ts | 61 +++++++++++++++++++ packages/sample/src/command/list.ts | 3 +- 8 files changed, 66 insertions(+), 74 deletions(-) create mode 100644 packages/sample/src/adb-setup.ts diff --git a/package-lock.json b/package-lock.json index 079564c5..9a0338e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7841,20 +7841,16 @@ "version": "0.1.0", "dependencies": { "@rev-robotics/rev-hub-core": "*", - "@rev-robotics/rhsplib": "*", "axios": "^1.4.0", "isomorphic-ws": "^5.0.0", - "semver": "^7.5.1", - "serialport": "^10.5.0" + "semver": "^7.5.1" }, "devDependencies": { "@types/node": "^16.18.18", - "@types/node-forge": "^1.3.2", "@types/semver": "^7.5.0", "typescript": "^5.0.2" }, "peerDependencies": { - "@u4/adbkit": ">= 4.1.19", "get-port": "^6.1.2" } }, @@ -7878,7 +7874,6 @@ "version": "0.1.0", "dependencies": { "@rev-robotics/rev-hub-core": "*", - "@rev-robotics/rhsplib": "*", "serialport": "^10.5.0" }, "devDependencies": { diff --git a/packages/control-hub/package.json b/packages/control-hub/package.json index c5002852..ce00d9d8 100644 --- a/packages/control-hub/package.json +++ b/packages/control-hub/package.json @@ -5,21 +5,17 @@ "main": "dist/index.js", "type": "module", "dependencies": { - "serialport": "^10.5.0", "isomorphic-ws": "^5.0.0", "axios": "^1.4.0", "semver": "^7.5.1", - "@rev-robotics/rhsplib": "*", "@rev-robotics/rev-hub-core": "*" }, "peerDependencies": { - "@u4/adbkit": ">= 4.1.19", "get-port": "^6.1.2" }, "devDependencies": { "@types/node": "^16.18.18", "@types/semver": "^7.5.0", - "@types/node-forge": "^1.3.2", "typescript": "^5.0.2" }, "scripts": { diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index ef4033c8..bb85d757 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -1,6 +1,4 @@ import { ControlHubInternal } from "./internal/ControlHub.js"; -import { Adb, DeviceClient } from "@u4/adbkit"; -import getPort from "get-port"; import { ControlHub } from "@rev-robotics/rev-hub-core"; export async function openConnectedControlHub(): Promise { @@ -11,43 +9,6 @@ export async function openConnectedControlHub(): Promise } } -export async function openUsbControlHubs(): Promise { - let adbClient = Adb.createClient(); - let controlHubs: ControlHub[] = []; - - let devices = await adbClient.listDevices(); - for (const device of devices) { - let deviceClient = device.getClient(); - let isHub = await isControlHub(deviceClient); - if (isHub) { - let port = await configureHubTcp(deviceClient); - let serialNumber = device.id; - - let hub = new ControlHubInternal(serialNumber); - await hub.open("127.0.0.1", (port + 1).toString()); - controlHubs.push(hub); - } - } - - return controlHubs; -} - -async function configureHubTcp(deviceClient: DeviceClient): Promise { - let port = await findAdjacentPorts(); - await deviceClient.forward(`tcp:${port}`, `tcp:8080`); - await deviceClient.forward(`tcp:${port + 1}`, `tcp:8081`); - - return port; -} - -async function isControlHub(deviceClient: DeviceClient): Promise { - let serialasusb = await deviceClient.execOut( - "getprop persist.ftcandroid.serialasusb", - "utf8", - ); - return serialasusb.startsWith("true"); -} - async function createWiFiControlHub(): Promise { let hub = new ControlHubInternal("Placeholder"); @@ -59,23 +20,3 @@ async function createWiFiControlHub(): Promise { return hub; } - -/** - * Returns the first of two adjacent ports. - * @param host - */ -export async function findAdjacentPorts(host: string = "127.0.0.1"): Promise { - try { - //const getPort = (await import("get-port")).default; - let port = await getPort({ host: host }); - let adjacent = await getPort({ host: host, port: port + 1 }); - if (adjacent === port + 1) return port; - else { - return await findAdjacentPorts(host); - } - } catch (e) { - console.log("Got error checking ports"); - console.log(e); - throw e; - } -} diff --git a/packages/control-hub/src/index.ts b/packages/control-hub/src/index.ts index e5d4c645..43bfba1b 100644 --- a/packages/control-hub/src/index.ts +++ b/packages/control-hub/src/index.ts @@ -1 +1 @@ -export { openConnectedControlHub, openUsbControlHubs } from "./discovery.js"; +export { openConnectedControlHub } from "./discovery.js"; diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index f8cf0e16..c2318f04 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -16,7 +16,6 @@ import { import axios from "axios"; import semver from "semver"; import WebSocket from "isomorphic-ws"; -import adb from "@u4/adbkit"; import { ControlHub, ExpansionHub, diff --git a/packages/expansion-hub/package.json b/packages/expansion-hub/package.json index 4af5912c..5c54e88f 100644 --- a/packages/expansion-hub/package.json +++ b/packages/expansion-hub/package.json @@ -6,8 +6,7 @@ "type": "module", "dependencies": { "serialport": "^10.5.0", - "@rev-robotics/rev-hub-core": "*", - "@rev-robotics/rhsplib": "*" + "@rev-robotics/rev-hub-core": "*" }, "devDependencies": { "@types/node": "^16.18.18", diff --git a/packages/sample/src/adb-setup.ts b/packages/sample/src/adb-setup.ts new file mode 100644 index 00000000..f526a006 --- /dev/null +++ b/packages/sample/src/adb-setup.ts @@ -0,0 +1,61 @@ +import { Adb, DeviceClient } from "@u4/adbkit"; +import getPort from "get-port"; +import { ControlHub } from "@rev-robotics/rev-hub-core"; +import { ControlHubInternal } from "@rev-robotics/control-hub/dist/internal/ControlHub.js"; + +export async function openUsbControlHubs(): Promise { + let adbClient = Adb.createClient(); + let controlHubs: ControlHub[] = []; + + let devices = await adbClient.listDevices(); + for (const device of devices) { + let deviceClient = device.getClient(); + let isHub = await isControlHub(deviceClient); + if (isHub) { + let port = await configureHubTcp(deviceClient); + let serialNumber = device.id; + + let hub = new ControlHubInternal(serialNumber); + await hub.open("127.0.0.1", (port + 1).toString()); + controlHubs.push(hub); + } + } + + return controlHubs; +} + +async function isControlHub(deviceClient: DeviceClient): Promise { + let serialasusb = await deviceClient.execOut( + "getprop persist.ftcandroid.serialasusb", + "utf8", + ); + return serialasusb.startsWith("true"); +} + +async function configureHubTcp(deviceClient: DeviceClient): Promise { + let port = await findAdjacentPorts(); + await deviceClient.forward(`tcp:${port}`, `tcp:8080`); + await deviceClient.forward(`tcp:${port + 1}`, `tcp:8081`); + + return port; +} + +/** + * Returns the first of two adjacent ports. + * @param host + */ +export async function findAdjacentPorts(host: string = "127.0.0.1"): Promise { + try { + //const getPort = (await import("get-port")).default; + let port = await getPort({ host: host }); + let adjacent = await getPort({ host: host, port: port + 1 }); + if (adjacent === port + 1) return port; + else { + return await findAdjacentPorts(host); + } + } catch (e) { + console.log("Got error checking ports"); + console.log(e); + throw e; + } +} diff --git a/packages/sample/src/command/list.ts b/packages/sample/src/command/list.ts index bb864f94..5492e19b 100644 --- a/packages/sample/src/command/list.ts +++ b/packages/sample/src/command/list.ts @@ -1,7 +1,8 @@ import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; import { hubHierarchyToString } from "../HubStringify.js"; -import { openConnectedControlHub, openUsbControlHubs } from "@rev-robotics/control-hub"; +import { openConnectedControlHub } from "@rev-robotics/control-hub"; import { ExpansionHub } from "@rev-robotics/rev-hub-core"; +import { openUsbControlHubs } from "../adb-setup.js"; export async function list() { let usbControlHubs = await openUsbControlHubs(); From f4a6585a735f04bd7462f3dc452e0c57486d82fc Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 15:23:01 -0500 Subject: [PATCH 018/148] Remove override of target --- packages/control-hub/tsconfig.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/control-hub/tsconfig.json b/packages/control-hub/tsconfig.json index 11324309..5c86a3d2 100644 --- a/packages/control-hub/tsconfig.json +++ b/packages/control-hub/tsconfig.json @@ -1,9 +1,7 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "esModuleInterop": true, "outDir": "./dist", - "rootDir": "./src", - "target": "es2017" + "rootDir": "./src" } } From f4afa3ca0ca6a567b61f0b37caaa10f9885fd16a Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 15:30:49 -0500 Subject: [PATCH 019/148] Add note on dependencies in README --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 8b459165..ef8b725d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,24 @@ This project enables Node.js applications to control devices that speak the REV Hub Serial Protocol (such as the REV Robotics Expansion Hub). +## Control Hub dependencies + +The Control Hub package has two optional dependencies. + +### ws + +If you are using node.js and wish to communicate +with a Control Hub via WiFi, you will need to add +a dependency on [ws](https://www.npmjs.com/package/ws). + +### adbkit + +If you wish to communicate with a Control Hub over +USB, you will need to set up port forwarding. This +requires a dependency on [adbkit](https://www.npmjs.com/package/adbkit). +See [adbkit setup](packages/sample/src/adb-setup.ts) +for an example of setting up port forwarding. + ## Package structure This project uses [lerna](https://lerna.js.org) for From ab9b52a59e2e5b8e112ab3b0fea35e830bdacffd Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 15:33:55 -0500 Subject: [PATCH 020/148] loosen version requirement for get-port --- package-lock.json | 2 +- packages/control-hub/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9a0338e7..4ca44271 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7851,7 +7851,7 @@ "typescript": "^5.0.2" }, "peerDependencies": { - "get-port": "^6.1.2" + "get-port": "6.x" } }, "packages/core": { diff --git a/packages/control-hub/package.json b/packages/control-hub/package.json index ce00d9d8..08750822 100644 --- a/packages/control-hub/package.json +++ b/packages/control-hub/package.json @@ -11,7 +11,7 @@ "@rev-robotics/rev-hub-core": "*" }, "peerDependencies": { - "get-port": "^6.1.2" + "get-port": "6.x" }, "devDependencies": { "@types/node": "^16.18.18", From ed8caaaa5402d62d7b3b0e5f5611e5d4609f1707 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Mon, 5 Jun 2023 14:34:12 -0500 Subject: [PATCH 021/148] Send address in commands --- packages/control-hub/src/internal/ControlHub.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index c2318f04..24945fc1 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -70,7 +70,10 @@ export class ControlHubInternal implements ControlHub { return new Promise((resolve, reject) => { this.webSocketConnection.on("open", async () => { - this.moduleAddress = await this.sendCommand("getModuleAddress", {}); + this.moduleAddress = await this.sendCommand("getModuleAddress", { + serialNumber: "Embedded", + moduleAddress: 173, + }); resolve(); }); }); From 15f626f4a57a33342ff2d15822b1de81340a238d Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Mon, 5 Jun 2023 17:03:26 -0500 Subject: [PATCH 022/148] Send commands when control hub methods called --- packages/control-hub/src/index.ts | 12 + .../control-hub/src/internal/ControlHub.ts | 456 ++++++++++++++---- packages/sample/src/adb-setup.ts | 5 +- 3 files changed, 373 insertions(+), 100 deletions(-) diff --git a/packages/control-hub/src/index.ts b/packages/control-hub/src/index.ts index 43bfba1b..14bf7881 100644 --- a/packages/control-hub/src/index.ts +++ b/packages/control-hub/src/index.ts @@ -1 +1,13 @@ +import { ControlHubInternal } from "./internal/ControlHub.js"; +import { ControlHub } from "@rev-robotics/rev-hub-core"; + export { openConnectedControlHub } from "./discovery.js"; + +export async function openControlHub( + serialNumber: string, + port: number, +): Promise { + let hub = new ControlHubInternal(serialNumber); + await hub.open("127.0.0.1", (port + 1).toString()); + return hub; +} diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 24945fc1..86ae1956 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -108,27 +108,55 @@ export class ControlHubInternal implements ControlHub { } async getBulkInputData(): Promise { + let result = await this.sendCommand("getBulkInputData", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }); throw new Error("not implemented"); } - getDigitalAllInputs(): Promise { - throw new Error("not implemented"); + async getDigitalAllInputs(): Promise { + return await this.sendCommand("getAllDigitalInputs", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }); } async getDigitalDirection(dioPin: number): Promise { - throw new Error("not implemented"); + let isOutput = await this.sendCommand("getDigitalDirection", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + channel: dioPin, + }); + + return isOutput ? DIODirection.Output : DIODirection.Input; } - getDigitalSingleInput(dioPin: number): Promise { - throw new Error("not implemented"); + async getDigitalSingleInput(dioPin: number): Promise { + return await this.sendCommand("getDigitalInput", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + channel: dioPin, + }); } - getFTDIResetControl(): Promise { - throw new Error("not implemented"); + async getFTDIResetControl(): Promise { + return await this.sendCommand("getFtdiResetControl", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }); } - getI2CChannelConfiguration(i2cChannel: number): Promise { - throw new Error("not implemented"); + async getI2CChannelConfiguration(i2cChannel: number): Promise { + let speedCode = await this.sendCommand("getI2CChannelConfiguration", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + channel: i2cChannel, + }); + + return speedCode == 1 + ? I2CSpeedCode.SpeedCode400_Kbps + : I2CSpeedCode.SpeedCode100_Kbps; } getI2CReadStatus(i2cChannel: number): Promise { @@ -139,95 +167,198 @@ export class ControlHubInternal implements ControlHub { throw new Error("not implemented"); } - getInterfacePacketID(interfaceName: string, functionNumber: number): Promise { - return Promise.resolve(0); + async getInterfacePacketID( + interfaceName: string, + functionNumber: number, + ): Promise { + return await this.sendCommand("getInterfacePacketId", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + interfaceName: interfaceName, + functionNumber: functionNumber, + }); } - getModuleLedColor(): Promise { - throw new Error("not implemented"); + async getModuleLedColor(): Promise { + let result: { r: number; g: number; b: number } = await this.sendCommand( + "getLedColor", + { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }, + ); + + return { + red: result.r, + green: result.g, + blue: result.b, + }; } getModuleLedPattern(): Promise { throw new Error("not implemented"); } - getModuleStatus(clearStatusAfterResponse: boolean): Promise { - throw new Error("not implemented"); + async getModuleStatus(clearStatusAfterResponse: boolean): Promise { + return await this.sendCommand("getModuleStatus", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }); } - getMotorAtTarget(motorChannel: number): Promise { - return Promise.resolve(false); + async getMotorAtTarget(motorChannel: number): Promise { + return await this.sendCommand("getIsMotorAtTarget", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }); } - getMotorChannelCurrentAlertLevel(motorChannel: number): Promise { - return Promise.resolve(0); + async getMotorChannelCurrentAlertLevel(motorChannel: number): Promise { + return await this.sendCommand("getMotorAlertLevel", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }); } - getMotorChannelEnable(motorChannel: number): Promise { - return Promise.resolve(false); + async getMotorChannelEnable(motorChannel: number): Promise { + return await this.sendCommand("getMotorChannelEnable", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }); } - getMotorChannelMode( + async getMotorChannelMode( motorChannel: number, ): Promise<{ motorMode: number; floatAtZero: boolean }> { - return Promise.resolve({ floatAtZero: false, motorMode: 0 }); + return await this.sendCommand("getMotorMode", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }); } - getMotorConstantPower(motorChannel: number): Promise { - return Promise.resolve(0); + async getMotorConstantPower(motorChannel: number): Promise { + return await this.sendCommand("getMotorConstantPower", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }); } - getMotorEncoderPosition(motorChannel: number): Promise { - return Promise.resolve(0); + async getMotorEncoderPosition(motorChannel: number): Promise { + return await this.sendCommand("getMotorEncoderPosition", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }); } - getMotorPIDCoefficients( + async getMotorPIDCoefficients( motorChannel: number, motorMode: number, ): Promise { - throw new Error("not implemented"); + let result: { p: number; i: number; d: number } = await this.sendCommand( + "getMotorPidCoefficients", + { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }, + ); + + return { + P: result.p, + I: result.i, + D: result.d, + }; } - getMotorTargetPosition( + async getMotorTargetPosition( motorChannel: number, ): Promise<{ targetPosition: number; targetTolerance: number }> { - return Promise.resolve({ targetPosition: 0, targetTolerance: 0 }); + let result: { targetPositionCounts: number; targetToleranceCounts: number } = + await this.sendCommand("getMotorTargetPosition", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }); + + return { + targetPosition: result.targetPositionCounts, + targetTolerance: result.targetToleranceCounts, + }; } - getMotorTargetVelocity(motorChannel: number): Promise { - return Promise.resolve(0); + async getMotorTargetVelocity(motorChannel: number): Promise { + return await this.sendCommand("getMotorTargetVelocity", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }); } - getPhoneChargeControl(): Promise { - return Promise.resolve(false); + async getPhoneChargeControl(): Promise { + return await this.sendCommand("getPhoneChargeControl", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }); } - getServoConfiguration(servoChannel: number): Promise { - return Promise.resolve(0); + async getServoConfiguration(servoChannel: number): Promise { + return await this.sendCommand("getServoConfiguration", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + servoChannel: servoChannel, + }); } - getServoEnable(servoChannel: number): Promise { - return Promise.resolve(false); + async getServoEnable(servoChannel: number): Promise { + return await this.sendCommand("getServoEnable", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + servoChannel: servoChannel, + }); } - getServoPulseWidth(servoChannel: number): Promise { - return Promise.resolve(0); + async getServoPulseWidth(servoChannel: number): Promise { + return await this.sendCommand("getServoPulseWidth", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + servoChannel: servoChannel, + }); } - injectDataLogHint(hintText: string): Promise { - throw new Error("not implemented"); + async injectDataLogHint(hintText: string): Promise { + await this.sendCommand("injectDebugLogHint", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + hint: hintText, + }); } isExpansionHub(): this is ExpansionHub { - throw new Error("not implemented"); + return true; } on(eventName: "error", listener: (error: Error) => void): RevHub { throw new Error("not implemented"); } - queryInterface(interfaceName: string): Promise { - throw new Error("not implemented"); + async queryInterface(interfaceName: string): Promise { + let result: { name: string; firstPacketId: number; numberIds: number } = + await this.sendCommand("queryInterface", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + interfaceName: interfaceName, + }); + + return { + name: result.name, + firstPacketID: result.firstPacketId, + numberIDValues: result.numberIds, + }; } readI2CMultipleBytes( @@ -242,27 +373,37 @@ export class ControlHubInternal implements ControlHub { throw new Error("not implemented"); } - readVersion(): Promise { + async readVersion(): Promise { + let versionString = await this.readVersionString(); + //ToDo(landry) parse version string throw new Error("not implemented"); } - readVersionString(): Promise { - return Promise.resolve(""); + async readVersionString(): Promise { + return await this.sendCommand("readVersionString", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }); } - resetMotorEncoder(motorChannel: number): Promise { - throw new Error("not implemented"); + async resetMotorEncoder(motorChannel: number): Promise { + await this.sendCommand("resetMotorEncoder", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }); } - sendFailSafe(): Promise { - throw new Error("not implemented"); + async sendFailSafe(): Promise { + await this.sendCommand("readVersionString", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }); } - sendKeepAlive(): Promise { - throw new Error("not implemented"); - } + async sendKeepAlive(): Promise {} - sendReadCommand(packetTypeID: number, payload: number[]): Promise { + async sendReadCommand(packetTypeID: number, payload: number[]): Promise { return Promise.resolve([]); } @@ -270,105 +411,226 @@ export class ControlHubInternal implements ControlHub { return Promise.resolve([]); } - setDebugLogLevel( + async setDebugLogLevel( debugGroup: DebugGroup, verbosityLevel: VerbosityLevel, ): Promise { - throw new Error("not implemented"); + await this.sendCommand("readVersionString", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + debugGroup: debugGroup, + verbosityLevel: verbosityLevel, + }); } - setDigitalAllOutputs(bitPackedField: number): Promise { - throw new Error("not implemented"); + async setDigitalAllOutputs(bitPackedField: number): Promise { + await this.sendCommand("readVersionString", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + bitField: bitPackedField, + }); } - setDigitalDirection(dioPin: number, direction: DIODirection): Promise { - throw new Error("not implemented"); + async setDigitalDirection(dioPin: number, direction: DIODirection): Promise { + await this.sendCommand("readVersionString", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + pin: dioPin, + isOutput: direction == DIODirection.Output, + }); } - setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { - throw new Error("not implemented"); + async setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { + await this.sendCommand("readVersionString", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + pin: dioPin, + value: value ?? false, + }); } - setFTDIResetControl(ftdiResetControl: boolean): Promise { - throw new Error("not implemented"); + async setFTDIResetControl(ftdiResetControl: boolean): Promise { + await this.sendCommand("setFtdiResetControl", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }); } - setI2CChannelConfiguration( + async setI2CChannelConfiguration( i2cChannel: number, speedCode: I2CSpeedCode, ): Promise { - throw new Error("not implemented"); + await this.sendCommand("setI2CChannelConfiguration", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + i2cChannel: i2cChannel, + speedCode: speedCode, + }); } - setModuleLedColor(red: number, green: number, blue: number): Promise { - throw new Error("not implemented"); + async setModuleLedColor(red: number, green: number, blue: number): Promise { + await this.sendCommand("setLedColor", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + r: red, + g: green, + b: blue, + }); } - setModuleLedPattern(ledPattern: LEDPattern): Promise { - throw new Error("not implemented"); + async setModuleLedPattern(ledPattern: LEDPattern): Promise { + await this.sendCommand("setLedColor", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + rgbtPatternStep0: ledPattern.rgbtPatternStep0, + rgbtPatternStep1: ledPattern.rgbtPatternStep1, + rgbtPatternStep2: ledPattern.rgbtPatternStep2, + rgbtPatternStep3: ledPattern.rgbtPatternStep3, + rgbtPatternStep4: ledPattern.rgbtPatternStep4, + rgbtPatternStep5: ledPattern.rgbtPatternStep5, + rgbtPatternStep6: ledPattern.rgbtPatternStep6, + rgbtPatternStep7: ledPattern.rgbtPatternStep7, + rgbtPatternStep8: ledPattern.rgbtPatternStep8, + rgbtPatternStep9: ledPattern.rgbtPatternStep9, + rgbtPatternStep10: ledPattern.rgbtPatternStep10, + rgbtPatternStep11: ledPattern.rgbtPatternStep11, + rgbtPatternStep12: ledPattern.rgbtPatternStep12, + rgbtPatternStep13: ledPattern.rgbtPatternStep13, + rgbtPatternStep14: ledPattern.rgbtPatternStep14, + rgbtPatternStep15: ledPattern.rgbtPatternStep15, + }); } - setMotorChannelCurrentAlertLevel( + async setMotorChannelCurrentAlertLevel( motorChannel: number, currentLimit_mA: number, ): Promise { - throw new Error("not implemented"); + await this.sendCommand("setMotorAlertLevel", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + currentLimit_mA: currentLimit_mA, + }); } - setMotorChannelEnable(motorChannel: number, enable: boolean): Promise { - throw new Error("not implemented"); + async setMotorChannelEnable(motorChannel: number, enable: boolean): Promise { + await this.sendCommand("setMotorEnabled", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + enable: enable, + }); } - setMotorChannelMode( + async setMotorChannelMode( motorChannel: number, motorMode: number, floatAtZero: boolean, ): Promise { - throw new Error("not implemented"); + await this.sendCommand("setMotorChannelMode", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + motorMode: motorMode, + floatAtZero: floatAtZero, + }); } - setMotorConstantPower(motorChannel: number, powerLevel: number): Promise { - throw new Error("not implemented"); + async setMotorConstantPower(motorChannel: number, powerLevel: number): Promise { + await this.sendCommand("setMotorConstantPower", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + motorPower: powerLevel, + }); } - setMotorPIDCoefficients( + async setMotorPIDCoefficients( motorChannel: number, motorMode: number, pid: PIDCoefficients, ): Promise { - throw new Error("not implemented"); + await this.sendCommand("setMotorPidCoefficients", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + motorMode: motorMode, + p: pid.P, + i: pid.I, + d: pid.D, + }); } - setMotorTargetPosition( + async setMotorTargetPosition( motorChannel: number, targetPosition_counts: number, targetTolerance_counts: number, ): Promise { - throw new Error("not implemented"); + await this.sendCommand("setMotorTargetPosition", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + targetPositionCounts: targetPosition_counts, + targetToleranceCounts: targetTolerance_counts, + }); } - setMotorTargetVelocity(motorChannel: number, velocity_cps: number): Promise { - throw new Error("not implemented"); + async setMotorTargetVelocity( + motorChannel: number, + velocity_cps: number, + ): Promise { + await this.sendCommand("setMotorTargetVelocity", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + velocityCps: velocity_cps, + }); } - setNewModuleAddress(newModuleAddress: number): Promise { - throw new Error("not implemented"); + async setNewModuleAddress(newModuleAddress: number): Promise { + await this.sendCommand("setNewModuleAddress", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + address: newModuleAddress, + }); } - setPhoneChargeControl(chargeEnable: boolean): Promise { - throw new Error("not implemented"); + async setPhoneChargeControl(chargeEnable: boolean): Promise { + await this.sendCommand("setPhoneChargeControl", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + enabled: chargeEnable, + }); } - setServoConfiguration(servoChannel: number, framePeriod: number): Promise { - throw new Error("not implemented"); + async setServoConfiguration( + servoChannel: number, + framePeriod: number, + ): Promise { + await this.sendCommand("setServoConfiguration", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + servoChannel: servoChannel, + framePeriod: framePeriod, + }); } - setServoEnable(servoChannel: number, enable: boolean): Promise { - throw new Error("not implemented"); + async setServoEnable(servoChannel: number, enable: boolean): Promise { + await this.sendCommand("setServoEnable", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + servoChannel: servoChannel, + enabled: enable, + }); } - setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise { - throw new Error("not implemented"); + async setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise { + await this.sendCommand("setServoPulseWidth", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + servoChannel: servoChannel, + pulseWidth: pulseWidth, + }); } writeI2CMultipleBytes( diff --git a/packages/sample/src/adb-setup.ts b/packages/sample/src/adb-setup.ts index f526a006..61db9ef3 100644 --- a/packages/sample/src/adb-setup.ts +++ b/packages/sample/src/adb-setup.ts @@ -1,7 +1,7 @@ import { Adb, DeviceClient } from "@u4/adbkit"; import getPort from "get-port"; import { ControlHub } from "@rev-robotics/rev-hub-core"; -import { ControlHubInternal } from "@rev-robotics/control-hub/dist/internal/ControlHub.js"; +import { openControlHub } from "@rev-robotics/control-hub"; export async function openUsbControlHubs(): Promise { let adbClient = Adb.createClient(); @@ -15,8 +15,7 @@ export async function openUsbControlHubs(): Promise { let port = await configureHubTcp(deviceClient); let serialNumber = device.id; - let hub = new ControlHubInternal(serialNumber); - await hub.open("127.0.0.1", (port + 1).toString()); + let hub = await openControlHub(serialNumber, port); controlHubs.push(hub); } } From ad4b33f6c169938e1728682614c2f76f6314a35a Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 8 Jun 2023 11:16:37 -0500 Subject: [PATCH 023/148] Use control hubs for commands and fix incorrect key --- packages/control-hub/src/internal/ControlHub.ts | 4 ++-- packages/sample/src/command/analog.ts | 9 +++++---- packages/sample/src/command/servo.ts | 3 ++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 5d4ff5c9..1d9fb730 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -53,8 +53,8 @@ export class ControlHubInternal implements ControlHub { this.webSocketConnection.on("message", (data) => { let rawMessage = JSON.parse(data.toString()); - if (rawMessage.key !== undefined) { - let key = rawMessage.key; + if (rawMessage.commandKey !== undefined) { + let key = rawMessage.commandKey; let callback = this.currentActiveCommands.get(key); let response = rawMessage.response diff --git a/packages/sample/src/command/analog.ts b/packages/sample/src/command/analog.ts index 0c45a8a4..ab664ea1 100644 --- a/packages/sample/src/command/analog.ts +++ b/packages/sample/src/command/analog.ts @@ -1,7 +1,8 @@ import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; +import { openUsbControlHubs } from "../adb-setup.js"; export async function analog(channel: number, continuous: boolean) { - const hubs = await openConnectedExpansionHubs(); + const hubs = await openUsbControlHubs(); if (continuous) { while (true) { @@ -18,7 +19,7 @@ export async function analog(channel: number, continuous: boolean) { } export async function temperature(continuous: boolean) { - const hubs = await openConnectedExpansionHubs(); + const hubs = await openUsbControlHubs(); if (continuous) { while (true) { @@ -35,7 +36,7 @@ export async function temperature(continuous: boolean) { } export async function battery(continuous: boolean) { - const hubs = await openConnectedExpansionHubs(); + const hubs = await openUsbControlHubs(); if (continuous) { while (true) { @@ -52,7 +53,7 @@ export async function battery(continuous: boolean) { } export async function voltageRail(continuous: boolean) { - const hubs = await openConnectedExpansionHubs(); + const hubs = await openUsbControlHubs(); if (continuous) { while (true) { diff --git a/packages/sample/src/command/servo.ts b/packages/sample/src/command/servo.ts index 67b9093d..503e85b6 100644 --- a/packages/sample/src/command/servo.ts +++ b/packages/sample/src/command/servo.ts @@ -1,7 +1,8 @@ import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; +import { openUsbControlHubs } from "../adb-setup.js"; export async function runServo(channel: number, pulseWidth: number, framePeriod: number) { - const hubs = await openConnectedExpansionHubs(); + const hubs = await openUsbControlHubs(); await hubs[0].setServoConfiguration(channel, framePeriod); await hubs[0].setServoPulseWidth(channel, pulseWidth); From e659ed4db26967160ff2f5354a083bedf3654c55 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 8 Jun 2023 11:41:25 -0500 Subject: [PATCH 024/148] apply changes to be compatible with new manual control changes --- packages/control-hub/src/internal/ControlHub.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 1d9fb730..1e609e1a 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -70,6 +70,14 @@ export class ControlHubInternal implements ControlHub { return new Promise((resolve, reject) => { this.webSocketConnection.on("open", async () => { + console.log("Starting manual control op mode"); + let apiVersion: { majorVersion: string; minorVersion: string } = + await this.sendCommand("start", {}); + + console.log( + `API version is ${apiVersion.majorVersion}.${apiVersion.minorVersion}`, + ); + this.moduleAddress = await this.sendCommand("getModuleAddress", { serialNumber: "Embedded", moduleAddress: 173, @@ -100,7 +108,9 @@ export class ControlHubInternal implements ControlHub { } close(): void { - this.webSocketConnection.close(); + this.sendCommand("stop", {}).then(() => { + this.webSocketConnection.close(); + }); } async getAnalogInput(channel: number): Promise { @@ -724,10 +734,11 @@ export class ControlHubInternal implements ControlHub { commandPayload: JSON.stringify(params), }; let payload = { - namespace: "ManualControl", + namespace: "MC", type: type, payload: JSON.stringify(messagePayload), }; + this.webSocketConnection?.send(JSON.stringify(payload)); return new Promise((resolve, reject) => { From b0ed49bac3c1c357b973e1f6b13fc09857b34ca0 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 8 Jun 2023 13:54:55 -0500 Subject: [PATCH 025/148] add timeout to control hub websocket commands --- packages/control-hub/src/internal/ControlHub.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 1e609e1a..b30679dc 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -22,7 +22,9 @@ import { ParentRevHub, RevHub, RevHubType, + TimeoutError, } from "@rev-robotics/rev-hub-core"; +import { clearTimeout } from "timers"; export class ControlHubInternal implements ControlHub { readonly isOpen: boolean = true; @@ -727,7 +729,7 @@ export class ControlHubInternal implements ControlHub { throw new Error("not implemented"); } - async sendCommand(type: string, params: P): Promise { + async sendCommand(type: string, params: P, timeout: number = 1000): Promise { let key = 0; let messagePayload = { key: key, @@ -741,7 +743,7 @@ export class ControlHubInternal implements ControlHub { this.webSocketConnection?.send(JSON.stringify(payload)); - return new Promise((resolve, reject) => { + let callbackPromise: Promise = new Promise((resolve, reject) => { this.currentActiveCommands.set(key, (response, error) => { if (response !== undefined) { resolve(response); @@ -752,6 +754,17 @@ export class ControlHubInternal implements ControlHub { } }); }); + + let timer!: NodeJS.Timer; + let timeoutPromise: Promise = new Promise((_, reject) => { + timer = setTimeout(() => { + reject(new TimeoutError()); + }, timeout); + }); + + return await Promise.race([callbackPromise, timeoutPromise]).finally(() => { + clearTimeout(timer); + }); } addChild(hub: RevHub): void { From 9999f8b79315c90e3030add90cd8f68f7f762d7a Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 8 Jun 2023 13:56:39 -0500 Subject: [PATCH 026/148] Add todo for closing (and resetting op mode) when websocket is closed --- packages/control-hub/src/internal/ControlHub.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index b30679dc..f1b948d5 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -70,6 +70,8 @@ export class ControlHubInternal implements ControlHub { } }); + //Todo(landry): determine if we should call close() on webSocketConnection.on("close") + return new Promise((resolve, reject) => { this.webSocketConnection.on("open", async () => { console.log("Starting manual control op mode"); From 54635656d4677bc4e9cdbcec0ee4cebd9d3ae230 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 8 Jun 2023 15:03:48 -0500 Subject: [PATCH 027/148] Track whether the control hub is connected --- packages/control-hub/src/internal/ControlHub.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index f1b948d5..8e753013 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -35,6 +35,11 @@ export class ControlHubInternal implements ControlHub { readonly serialNumber: string; readonly children: ReadonlyArray = []; + /** + * Whether the websocket is currently open. + */ + isConnected = false; + keyGenerator = 0; currentActiveCommands = new Map< any, @@ -70,10 +75,20 @@ export class ControlHubInternal implements ControlHub { } }); - //Todo(landry): determine if we should call close() on webSocketConnection.on("close") + this.webSocketConnection.on("close", () => { + console.log(`Connection was closed`); + this.isConnected = false; + }); + + this.webSocketConnection.on("error", (_: WebSocket, err: Error) => { + console.log("Websocket error"); + console.log(err); + this.isConnected = false; + }); return new Promise((resolve, reject) => { this.webSocketConnection.on("open", async () => { + this.isConnected = true; console.log("Starting manual control op mode"); let apiVersion: { majorVersion: string; minorVersion: string } = await this.sendCommand("start", {}); From 1598644563e881ce70fd9c085113ed3acecc043d Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 8 Jun 2023 15:07:30 -0500 Subject: [PATCH 028/148] convert some methods to private --- packages/control-hub/src/internal/ControlHub.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 8e753013..8aadbcb1 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -31,7 +31,6 @@ export class ControlHubInternal implements ControlHub { moduleAddress: number = 0; responseTimeoutMs: number = 0; type: RevHubType = RevHubType.ControlHub; - webSocketConnection!: WebSocket; readonly serialNumber: string; readonly children: ReadonlyArray = []; @@ -40,8 +39,9 @@ export class ControlHubInternal implements ControlHub { */ isConnected = false; - keyGenerator = 0; - currentActiveCommands = new Map< + private webSocketConnection!: WebSocket; + private keyGenerator = 0; + private currentActiveCommands = new Map< any, (response: any | undefined, error: any | undefined) => void >(); From 344acf7288a16f17e480702b553484d053f3b583 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 8 Jun 2023 15:44:32 -0500 Subject: [PATCH 029/148] remove logs --- packages/control-hub/src/internal/ControlHub.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 8aadbcb1..dc744905 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -89,14 +89,9 @@ export class ControlHubInternal implements ControlHub { return new Promise((resolve, reject) => { this.webSocketConnection.on("open", async () => { this.isConnected = true; - console.log("Starting manual control op mode"); let apiVersion: { majorVersion: string; minorVersion: string } = await this.sendCommand("start", {}); - console.log( - `API version is ${apiVersion.majorVersion}.${apiVersion.minorVersion}`, - ); - this.moduleAddress = await this.sendCommand("getModuleAddress", { serialNumber: "Embedded", moduleAddress: 173, From dae4912aaedf2eef87ba64dded9377ef236efed9 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 8 Jun 2023 15:52:12 -0500 Subject: [PATCH 030/148] update servo command --- packages/control-hub/src/internal/ControlHub.ts | 14 +++++++++++++- packages/sample/src/command/servo.ts | 9 ++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index dc744905..9ae1a868 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -34,6 +34,9 @@ export class ControlHubInternal implements ControlHub { readonly serialNumber: string; readonly children: ReadonlyArray = []; + private supportedManualControlMajorVersion = 0; + private supportedManualControlMinorVersion = 1; + /** * Whether the websocket is currently open. */ @@ -89,9 +92,18 @@ export class ControlHubInternal implements ControlHub { return new Promise((resolve, reject) => { this.webSocketConnection.on("open", async () => { this.isConnected = true; - let apiVersion: { majorVersion: string; minorVersion: string } = + let apiVersion: { majorVersion: number; minorVersion: number } = await this.sendCommand("start", {}); + if ( + apiVersion.majorVersion != this.supportedManualControlMajorVersion || + apiVersion.minorVersion < this.supportedManualControlMinorVersion + ) { + throw new Error( + `API Version ${apiVersion.majorVersion}.${apiVersion.minorVersion} is not supported`, + ); + } + this.moduleAddress = await this.sendCommand("getModuleAddress", { serialNumber: "Embedded", moduleAddress: 173, diff --git a/packages/sample/src/command/servo.ts b/packages/sample/src/command/servo.ts index 503e85b6..ea6461e2 100644 --- a/packages/sample/src/command/servo.ts +++ b/packages/sample/src/command/servo.ts @@ -4,7 +4,10 @@ import { openUsbControlHubs } from "../adb-setup.js"; export async function runServo(channel: number, pulseWidth: number, framePeriod: number) { const hubs = await openUsbControlHubs(); - await hubs[0].setServoConfiguration(channel, framePeriod); - await hubs[0].setServoPulseWidth(channel, pulseWidth); - await hubs[0].setServoEnable(channel, true); + for (let hub of hubs) { + await hub.setServoConfiguration(channel, framePeriod); + await hub.setServoPulseWidth(channel, pulseWidth); + await hub.setServoEnable(channel, true); + hub.close(); + } } From 69d2a4aaabe0128772adc5cc680a5ce6252292d7 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 9 Jun 2023 13:19:39 -0500 Subject: [PATCH 031/148] make compatible with latest control hub changes --- package-lock.json | 226 +++++------------- .../control-hub/src/internal/ControlHub.ts | 8 +- packages/rhsplib/package.json | 3 +- packages/sample/src/adb-setup.ts | 2 +- packages/sample/src/command/servo.ts | 5 +- 5 files changed, 71 insertions(+), 173 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c34ded6..b383a5bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -104,8 +104,7 @@ }, "node_modules/@devicefarmer/minicap-prebuilt": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@devicefarmer/minicap-prebuilt/-/minicap-prebuilt-2.7.1.tgz", - "integrity": "sha512-XM+mPIA9hgwSF4eOq0RnKSXycj2rLNm3Xsl7MM0kG3CtTpX3/J0AA8P+v8zWiGNCMxyhl2VwY52nmQE/QwN3zg==", + "license": "Apache-2.0", "optional": true }, "node_modules/@gar/promisify": { @@ -1787,28 +1786,23 @@ }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -1816,28 +1810,23 @@ }, "node_modules/@protobufjs/float": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + "license": "BSD-3-Clause" }, "node_modules/@rev-robotics/control-hub": { "resolved": "packages/control-hub", @@ -2019,17 +2008,15 @@ }, "node_modules/@types/debug": { "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/ms": "*" } }, "node_modules/@types/long": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + "license": "MIT" }, "node_modules/@types/minimatch": { "version": "3.0.5", @@ -2043,9 +2030,8 @@ }, "node_modules/@types/ms": { "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { "version": "16.18.25", @@ -2053,9 +2039,8 @@ }, "node_modules/@types/node-forge": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.2.tgz", - "integrity": "sha512-TzX3ahoi9xbmaoT58smrBu7oa6dQXb/+PTNCslZyD/55tlJ/osofIMClzZsoo6buDFrg7e4DvVGkZqVgv6OLxw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2072,23 +2057,20 @@ }, "node_modules/@types/semver": { "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/ws": { "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@u4/adbkit": { "version": "4.1.19", - "resolved": "https://registry.npmjs.org/@u4/adbkit/-/adbkit-4.1.19.tgz", - "integrity": "sha512-NoPuiYKiv+wTS1qvfZ+GEJXUd4poxJQORLnncoPSi99+hxU0T/xSnv3V3MdFc45IS3IhSxN6eU0AVRP8xvgq+g==", + "license": "Apache-2.0", "dependencies": { "@u4/adbkit-logcat": "2.1.2", "@u4/adbkit-monkey": "^1.0.5", @@ -2118,32 +2100,28 @@ }, "node_modules/@u4/adbkit-logcat": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@u4/adbkit-logcat/-/adbkit-logcat-2.1.2.tgz", - "integrity": "sha512-mCAuqwWCA2MXYP8nfPJe9IJQ/aTkiFCVvF+qnsBXQ5ceaQOnw2JKNQxjz5Gw7dhYZ9iazvcxg6FNhyec5pfHeQ==", + "license": "Apache-2.0", "engines": { "node": ">= 12.20.0" } }, "node_modules/@u4/adbkit-monkey": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@u4/adbkit-monkey/-/adbkit-monkey-1.0.5.tgz", - "integrity": "sha512-6Hoz8EeKVK3eEJAGR44yzclADhA/5Q4KDlTtegMY4Dl5VMGq+tm1HtrmBvT++kftfrG64/H7xnrOwQ7DwQ2TlA==", + "license": "Apache-2.0", "engines": { "node": ">= 12.20.0" } }, "node_modules/@u4/adbkit/node_modules/commander": { "version": "9.4.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", - "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "license": "MIT", "engines": { "node": "^12.20.0 || >=14" } }, "node_modules/@u4/adbkit/node_modules/get-port": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", - "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -2153,13 +2131,11 @@ }, "node_modules/@u4/minicap-prebuilt": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@u4/minicap-prebuilt/-/minicap-prebuilt-1.0.0.tgz", - "integrity": "sha512-z+hfnXEZmlCjNUfk4EioIWOLGoMg44a63FWcLqym2xSJuGP9WGS3qJ6ZXjT6ErYsuzSLPR0LGzCqfhXkQs/NBA==" + "license": "Apache-2.0" }, "node_modules/@xmldom/xmldom": { "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.8.tgz", - "integrity": "sha512-0LNz4EY8B/8xXY86wMrQ4tz6zEHZv9ehFMJPm8u2gq5lQ71cfRKdaKyxfJAx5aUoyzx0qzgURblTisPGgz3d+Q==", + "license": "MIT", "engines": { "node": ">=10.0.0" } @@ -2934,9 +2910,8 @@ }, "node_modules/core-js": { "version": "3.30.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.30.2.tgz", - "integrity": "sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg==", "hasInstallScript": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -3582,8 +3557,7 @@ }, "node_modules/get-port": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-6.1.2.tgz", - "integrity": "sha512-BrGGraKm2uPqurfGVj/z97/zv8dPleC6x9JBNRTrDNtCkkRF4rPwrQXFgL7+I+q8QSdU4ntLQX2D7KIxSy8nGw==", + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -4307,8 +4281,7 @@ }, "node_modules/isomorphic-ws": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", - "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "license": "MIT", "peerDependencies": { "ws": "*" } @@ -4864,8 +4837,7 @@ }, "node_modules/long": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "license": "Apache-2.0" }, "node_modules/lru-cache": { "version": "7.18.3", @@ -5390,8 +5362,7 @@ }, "node_modules/node-forge": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } @@ -6404,8 +6375,7 @@ }, "node_modules/promise-duplex": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-duplex/-/promise-duplex-6.0.0.tgz", - "integrity": "sha512-ZL7rquzjTFzInDBeWYcsT+qddolNvzigahk6MI6qLSbQvlyRRCJkU3JztgaVunzvkH28smRa2Qu/cY9RXtSkgA==", + "license": "MIT", "dependencies": { "core-js": "^3.6.5", "promise-readable": "^6.0.0", @@ -6422,8 +6392,7 @@ }, "node_modules/promise-readable": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-readable/-/promise-readable-6.0.0.tgz", - "integrity": "sha512-5NxtmUswijvX5cAM0zPSy6yiCXH/eKBpiiBq6JfAUrmngMquMbzcBhF2qA+ocs4rYYKdvAfv3cOvZxADLtL1CA==", + "license": "MIT", "dependencies": { "core-js": "^3.6.5" }, @@ -6445,8 +6414,7 @@ }, "node_modules/promise-writable": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-writable/-/promise-writable-6.0.0.tgz", - "integrity": "sha512-b81zre/itgJFS7dwWzIdKNVVqvLiUxYRS/wolUB0H1YY/tAaS146XGKa4Q/5wCbsnXLyn0MCeV6f8HHe4iUHLg==", + "license": "MIT", "engines": { "node": ">=10.0.0" } @@ -6466,9 +6434,8 @@ }, "node_modules/protobufjs": { "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", "hasInstallScript": true, + "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -7761,8 +7728,7 @@ }, "node_modules/ws": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -7781,8 +7747,7 @@ }, "node_modules/xpath": { "version": "0.0.32", - "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz", - "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==", + "license": "MIT", "engines": { "node": ">=0.6.0" } @@ -7863,9 +7828,6 @@ "typescript": "^5.0.2" } }, - "packages/distance-sensor": { - "extraneous": true - }, "packages/expansion-hub": { "name": "@rev-robotics/expansion-hub", "version": "1.0.0", @@ -7980,8 +7942,6 @@ }, "@devicefarmer/minicap-prebuilt": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@devicefarmer/minicap-prebuilt/-/minicap-prebuilt-2.7.1.tgz", - "integrity": "sha512-XM+mPIA9hgwSF4eOq0RnKSXycj2rLNm3Xsl7MM0kG3CtTpX3/J0AA8P+v8zWiGNCMxyhl2VwY52nmQE/QwN3zg==", "optional": true }, "@gar/promisify": { @@ -9188,58 +9148,38 @@ } }, "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + "version": "1.1.2" }, "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + "version": "1.1.2" }, "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + "version": "2.0.4" }, "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + "version": "1.1.0" }, "@protobufjs/fetch": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "requires": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + "version": "1.0.2" }, "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + "version": "1.1.0" }, "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + "version": "1.1.2" }, "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + "version": "1.1.0" }, "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + "version": "1.1.0" }, "@rev-robotics/control-hub": { "version": "file:packages/control-hub", @@ -9353,17 +9293,13 @@ }, "@types/debug": { "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", "dev": true, "requires": { "@types/ms": "*" } }, "@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + "version": "4.0.2" }, "@types/minimatch": { "version": "3.0.5", @@ -9375,8 +9311,6 @@ }, "@types/ms": { "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", "dev": true }, "@types/node": { @@ -9384,8 +9318,6 @@ }, "@types/node-forge": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.2.tgz", - "integrity": "sha512-TzX3ahoi9xbmaoT58smrBu7oa6dQXb/+PTNCslZyD/55tlJ/osofIMClzZsoo6buDFrg7e4DvVGkZqVgv6OLxw==", "dev": true, "requires": { "@types/node": "*" @@ -9401,14 +9333,10 @@ }, "@types/semver": { "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, "@types/ws": { "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, "requires": { "@types/node": "*" @@ -9416,8 +9344,6 @@ }, "@u4/adbkit": { "version": "4.1.19", - "resolved": "https://registry.npmjs.org/@u4/adbkit/-/adbkit-4.1.19.tgz", - "integrity": "sha512-NoPuiYKiv+wTS1qvfZ+GEJXUd4poxJQORLnncoPSi99+hxU0T/xSnv3V3MdFc45IS3IhSxN6eU0AVRP8xvgq+g==", "requires": { "@devicefarmer/minicap-prebuilt": "^2.7.1", "@u4/adbkit-logcat": "2.1.2", @@ -9435,36 +9361,24 @@ }, "dependencies": { "commander": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", - "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==" + "version": "9.4.1" }, "get-port": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", - "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" + "version": "5.1.1" } } }, "@u4/adbkit-logcat": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@u4/adbkit-logcat/-/adbkit-logcat-2.1.2.tgz", - "integrity": "sha512-mCAuqwWCA2MXYP8nfPJe9IJQ/aTkiFCVvF+qnsBXQ5ceaQOnw2JKNQxjz5Gw7dhYZ9iazvcxg6FNhyec5pfHeQ==" + "version": "2.1.2" }, "@u4/adbkit-monkey": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@u4/adbkit-monkey/-/adbkit-monkey-1.0.5.tgz", - "integrity": "sha512-6Hoz8EeKVK3eEJAGR44yzclADhA/5Q4KDlTtegMY4Dl5VMGq+tm1HtrmBvT++kftfrG64/H7xnrOwQ7DwQ2TlA==" + "version": "1.0.5" }, "@u4/minicap-prebuilt": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@u4/minicap-prebuilt/-/minicap-prebuilt-1.0.0.tgz", - "integrity": "sha512-z+hfnXEZmlCjNUfk4EioIWOLGoMg44a63FWcLqym2xSJuGP9WGS3qJ6ZXjT6ErYsuzSLPR0LGzCqfhXkQs/NBA==" + "version": "1.0.0" }, "@xmldom/xmldom": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.8.tgz", - "integrity": "sha512-0LNz4EY8B/8xXY86wMrQ4tz6zEHZv9ehFMJPm8u2gq5lQ71cfRKdaKyxfJAx5aUoyzx0qzgURblTisPGgz3d+Q==" + "version": "0.8.8" }, "@yarnpkg/lockfile": { "version": "1.1.0", @@ -9973,9 +9887,7 @@ } }, "core-js": { - "version": "3.30.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.30.2.tgz", - "integrity": "sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg==" + "version": "3.30.2" }, "core-util-is": { "version": "1.0.3", @@ -10394,9 +10306,7 @@ } }, "get-port": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-6.1.2.tgz", - "integrity": "sha512-BrGGraKm2uPqurfGVj/z97/zv8dPleC6x9JBNRTrDNtCkkRF4rPwrQXFgL7+I+q8QSdU4ntLQX2D7KIxSy8nGw==" + "version": "6.1.2" }, "get-stream": { "version": "6.0.1", @@ -10855,8 +10765,6 @@ }, "isomorphic-ws": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", - "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", "requires": {} }, "jake": { @@ -11236,9 +11144,7 @@ } }, "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "version": "4.0.0" }, "lru-cache": { "version": "7.18.3", @@ -11569,9 +11475,7 @@ } }, "node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + "version": "1.3.1" }, "node-gyp": { "version": "9.3.1", @@ -12232,8 +12136,6 @@ }, "promise-duplex": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-duplex/-/promise-duplex-6.0.0.tgz", - "integrity": "sha512-ZL7rquzjTFzInDBeWYcsT+qddolNvzigahk6MI6qLSbQvlyRRCJkU3JztgaVunzvkH28smRa2Qu/cY9RXtSkgA==", "requires": { "core-js": "^3.6.5", "promise-readable": "^6.0.0", @@ -12246,8 +12148,6 @@ }, "promise-readable": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-readable/-/promise-readable-6.0.0.tgz", - "integrity": "sha512-5NxtmUswijvX5cAM0zPSy6yiCXH/eKBpiiBq6JfAUrmngMquMbzcBhF2qA+ocs4rYYKdvAfv3cOvZxADLtL1CA==", "requires": { "core-js": "^3.6.5" } @@ -12261,9 +12161,7 @@ } }, "promise-writable": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-writable/-/promise-writable-6.0.0.tgz", - "integrity": "sha512-b81zre/itgJFS7dwWzIdKNVVqvLiUxYRS/wolUB0H1YY/tAaS146XGKa4Q/5wCbsnXLyn0MCeV6f8HHe4iUHLg==" + "version": "6.0.0" }, "promzard": { "version": "0.3.0", @@ -12278,8 +12176,6 @@ }, "protobufjs": { "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -13126,14 +13022,10 @@ }, "ws": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "requires": {} }, "xpath": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz", - "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==" + "version": "0.0.32" }, "xtend": { "version": "4.0.2", diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 9ae1a868..c64f414f 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -54,11 +54,12 @@ export class ControlHubInternal implements ControlHub { } isParent(): this is ParentRevHub { - return this.serialNumber !== undefined; + return true; } async open(ip: string = "192.168.43.1", port: string = "8081"): Promise { this.webSocketConnection = new WebSocket(`ws://${ip}:${port}`); + console.log(`Opening on port ${port}`); this.webSocketConnection.on("message", (data) => { let rawMessage = JSON.parse(data.toString()); @@ -105,7 +106,7 @@ export class ControlHubInternal implements ControlHub { } this.moduleAddress = await this.sendCommand("getModuleAddress", { - serialNumber: "Embedded", + serialNumber: "(embedded)", moduleAddress: 173, }); resolve(); @@ -756,7 +757,7 @@ export class ControlHubInternal implements ControlHub { async sendCommand(type: string, params: P, timeout: number = 1000): Promise { let key = 0; let messagePayload = { - key: key, + commandKey: key, commandPayload: JSON.stringify(params), }; let payload = { @@ -772,6 +773,7 @@ export class ControlHubInternal implements ControlHub { if (response !== undefined) { resolve(response); } else { + console.error(`Got error for ${type}`); let e = new Error(); Object.assign(e, error); reject(e); diff --git a/packages/rhsplib/package.json b/packages/rhsplib/package.json index 9eb02fc4..d3a21bb4 100644 --- a/packages/rhsplib/package.json +++ b/packages/rhsplib/package.json @@ -24,7 +24,8 @@ }, "scripts": { "build": "tsc", - "install": "node-gyp-build \"node scripts/build-RHSPlib.mjs\"", + "install": "", + "postinstall": "node-gyp-build \"node scripts/build-RHSPlib.mjs\"", "prepublishOnly": "prebuildify --napi && tsc" }, "gypfile": true diff --git a/packages/sample/src/adb-setup.ts b/packages/sample/src/adb-setup.ts index 61db9ef3..317fe96b 100644 --- a/packages/sample/src/adb-setup.ts +++ b/packages/sample/src/adb-setup.ts @@ -15,7 +15,7 @@ export async function openUsbControlHubs(): Promise { let port = await configureHubTcp(deviceClient); let serialNumber = device.id; - let hub = await openControlHub(serialNumber, port); + let hub = await openControlHub("(embedded)", port); controlHubs.push(hub); } } diff --git a/packages/sample/src/command/servo.ts b/packages/sample/src/command/servo.ts index ea6461e2..bb245e52 100644 --- a/packages/sample/src/command/servo.ts +++ b/packages/sample/src/command/servo.ts @@ -8,6 +8,9 @@ export async function runServo(channel: number, pulseWidth: number, framePeriod: await hub.setServoConfiguration(channel, framePeriod); await hub.setServoPulseWidth(channel, pulseWidth); await hub.setServoEnable(channel, true); - hub.close(); + + setTimeout(() => { + hub.close(); + }, 10000); } } From 0b8ac611634bec1a1fb43d8df8b7216fc8d5612b Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 9 Jun 2023 14:25:36 -0500 Subject: [PATCH 032/148] use new id system for control hubs --- .../control-hub/src/internal/ControlHub.ts | 175 +++++++----------- 1 file changed, 64 insertions(+), 111 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index c64f414f..6e2440b4 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -34,6 +34,9 @@ export class ControlHubInternal implements ControlHub { readonly serialNumber: string; readonly children: ReadonlyArray = []; + private id: string | null; + private keyGenerator = 0; + private supportedManualControlMajorVersion = 0; private supportedManualControlMinorVersion = 1; @@ -43,14 +46,14 @@ export class ControlHubInternal implements ControlHub { isConnected = false; private webSocketConnection!: WebSocket; - private keyGenerator = 0; private currentActiveCommands = new Map< any, (response: any | undefined, error: any | undefined) => void >(); - constructor(serialNumber: string) { + constructor(serialNumber: string, id: string | null = null) { this.serialNumber = serialNumber; + this.id = id; } isParent(): this is ParentRevHub { @@ -142,86 +145,74 @@ export class ControlHubInternal implements ControlHub { async getAnalogInput(channel: number): Promise { return await this.sendCommand("getAnalogInput", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, channel: channel, }); } async get5VBusVoltage(): Promise { return await this.sendCommand("get5VBusVoltage", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getBatteryCurrent(): Promise { return await this.sendCommand("getBatteryCurrent", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getBatteryVoltage(): Promise { return await this.sendCommand("getBatteryVoltage", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getDigitalBusCurrent(): Promise { return await this.sendCommand("getDigitalBusCurrent", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getI2CCurrent(): Promise { return await this.sendCommand("getI2CCurrent", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getMotorCurrent(motorChannel: number): Promise { return await this.sendCommand("getMotorCurrent", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getServoCurrent(): Promise { return await this.sendCommand("getMotorCurrent", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getTemperature(): Promise { return await this.sendCommand("getTemperature", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getBulkInputData(): Promise { return await this.sendCommand("getBulkInputData", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getDigitalAllInputs(): Promise { return await this.sendCommand("getAllDigitalInputs", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getDigitalDirection(dioPin: number): Promise { let isOutput = await this.sendCommand("getDigitalDirection", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, channel: dioPin, }); @@ -230,23 +221,20 @@ export class ControlHubInternal implements ControlHub { async getDigitalSingleInput(dioPin: number): Promise { return await this.sendCommand("getDigitalInput", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, channel: dioPin, }); } async getFTDIResetControl(): Promise { return await this.sendCommand("getFtdiResetControl", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getI2CChannelConfiguration(i2cChannel: number): Promise { let speedCode = await this.sendCommand("getI2CChannelConfiguration", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, channel: i2cChannel, }); @@ -268,8 +256,7 @@ export class ControlHubInternal implements ControlHub { functionNumber: number, ): Promise { return await this.sendCommand("getInterfacePacketId", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, interfaceName: interfaceName, functionNumber: functionNumber, }); @@ -297,30 +284,26 @@ export class ControlHubInternal implements ControlHub { async getModuleStatus(clearStatusAfterResponse: boolean): Promise { return await this.sendCommand("getModuleStatus", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getMotorAtTarget(motorChannel: number): Promise { return await this.sendCommand("getIsMotorAtTarget", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getMotorChannelCurrentAlertLevel(motorChannel: number): Promise { return await this.sendCommand("getMotorAlertLevel", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, }); } async getMotorChannelEnable(motorChannel: number): Promise { return await this.sendCommand("getMotorChannelEnable", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, }); } @@ -329,24 +312,21 @@ export class ControlHubInternal implements ControlHub { motorChannel: number, ): Promise<{ motorMode: number; floatAtZero: boolean }> { return await this.sendCommand("getMotorMode", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, }); } async getMotorConstantPower(motorChannel: number): Promise { return await this.sendCommand("getMotorConstantPower", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, }); } async getMotorEncoderPosition(motorChannel: number): Promise { return await this.sendCommand("getMotorEncoderPosition", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, }); } @@ -389,47 +369,41 @@ export class ControlHubInternal implements ControlHub { async getMotorTargetVelocity(motorChannel: number): Promise { return await this.sendCommand("getMotorTargetVelocity", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, }); } async getPhoneChargeControl(): Promise { return await this.sendCommand("getPhoneChargeControl", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async getServoConfiguration(servoChannel: number): Promise { return await this.sendCommand("getServoConfiguration", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, servoChannel: servoChannel, }); } async getServoEnable(servoChannel: number): Promise { return await this.sendCommand("getServoEnable", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, servoChannel: servoChannel, }); } async getServoPulseWidth(servoChannel: number): Promise { return await this.sendCommand("getServoPulseWidth", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, servoChannel: servoChannel, }); } async injectDataLogHint(hintText: string): Promise { await this.sendCommand("injectDebugLogHint", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, hint: hintText, }); } @@ -477,23 +451,20 @@ export class ControlHubInternal implements ControlHub { async readVersionString(): Promise { return await this.sendCommand("readVersionString", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } async resetMotorEncoder(motorChannel: number): Promise { await this.sendCommand("resetMotorEncoder", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, }); } async sendFailSafe(): Promise { await this.sendCommand("readVersionString", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } @@ -512,8 +483,7 @@ export class ControlHubInternal implements ControlHub { verbosityLevel: VerbosityLevel, ): Promise { await this.sendCommand("readVersionString", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, debugGroup: debugGroup, verbosityLevel: verbosityLevel, }); @@ -521,16 +491,14 @@ export class ControlHubInternal implements ControlHub { async setDigitalAllOutputs(bitPackedField: number): Promise { await this.sendCommand("readVersionString", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, bitField: bitPackedField, }); } async setDigitalDirection(dioPin: number, direction: DioDirection): Promise { await this.sendCommand("readVersionString", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, pin: dioPin, isOutput: direction == DioDirection.Output, }); @@ -538,8 +506,7 @@ export class ControlHubInternal implements ControlHub { async setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { await this.sendCommand("readVersionString", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, pin: dioPin, value: value ?? false, }); @@ -547,8 +514,7 @@ export class ControlHubInternal implements ControlHub { async setFTDIResetControl(ftdiResetControl: boolean): Promise { await this.sendCommand("setFtdiResetControl", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, }); } @@ -557,8 +523,7 @@ export class ControlHubInternal implements ControlHub { speedCode: I2CSpeedCode, ): Promise { await this.sendCommand("setI2CChannelConfiguration", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, i2cChannel: i2cChannel, speedCode: speedCode, }); @@ -566,8 +531,7 @@ export class ControlHubInternal implements ControlHub { async setModuleLedColor(red: number, green: number, blue: number): Promise { await this.sendCommand("setLedColor", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, r: red, g: green, b: blue, @@ -575,9 +539,8 @@ export class ControlHubInternal implements ControlHub { } async setModuleLedPattern(ledPattern: LedPattern): Promise { - await this.sendCommand("setLedColor", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + await this.sendCommand("setLedPattern", { + id: this.id, rgbtPatternStep0: ledPattern.rgbtPatternStep0, rgbtPatternStep1: ledPattern.rgbtPatternStep1, rgbtPatternStep2: ledPattern.rgbtPatternStep2, @@ -602,8 +565,7 @@ export class ControlHubInternal implements ControlHub { currentLimit_mA: number, ): Promise { await this.sendCommand("setMotorAlertLevel", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, currentLimit_mA: currentLimit_mA, }); @@ -611,8 +573,7 @@ export class ControlHubInternal implements ControlHub { async setMotorChannelEnable(motorChannel: number, enable: boolean): Promise { await this.sendCommand("setMotorEnabled", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, enable: enable, }); @@ -624,8 +585,7 @@ export class ControlHubInternal implements ControlHub { floatAtZero: boolean, ): Promise { await this.sendCommand("setMotorChannelMode", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, motorMode: motorMode, floatAtZero: floatAtZero, @@ -634,8 +594,7 @@ export class ControlHubInternal implements ControlHub { async setMotorConstantPower(motorChannel: number, powerLevel: number): Promise { await this.sendCommand("setMotorConstantPower", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, motorPower: powerLevel, }); @@ -647,8 +606,7 @@ export class ControlHubInternal implements ControlHub { pid: PidCoefficients, ): Promise { await this.sendCommand("setMotorPidCoefficients", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, motorMode: motorMode, p: pid.p, @@ -663,8 +621,7 @@ export class ControlHubInternal implements ControlHub { targetTolerance_counts: number, ): Promise { await this.sendCommand("setMotorTargetPosition", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, targetPositionCounts: targetPosition_counts, targetToleranceCounts: targetTolerance_counts, @@ -676,8 +633,7 @@ export class ControlHubInternal implements ControlHub { velocity_cps: number, ): Promise { await this.sendCommand("setMotorTargetVelocity", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, motorChannel: motorChannel, velocityCps: velocity_cps, }); @@ -685,16 +641,14 @@ export class ControlHubInternal implements ControlHub { async setNewModuleAddress(newModuleAddress: number): Promise { await this.sendCommand("setNewModuleAddress", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, address: newModuleAddress, }); } async setPhoneChargeControl(chargeEnable: boolean): Promise { await this.sendCommand("setPhoneChargeControl", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, enabled: chargeEnable, }); } @@ -704,8 +658,7 @@ export class ControlHubInternal implements ControlHub { framePeriod: number, ): Promise { await this.sendCommand("setServoConfiguration", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, servoChannel: servoChannel, framePeriod: framePeriod, }); @@ -713,8 +666,7 @@ export class ControlHubInternal implements ControlHub { async setServoEnable(servoChannel: number, enable: boolean): Promise { await this.sendCommand("setServoEnable", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, servoChannel: servoChannel, enabled: enable, }); @@ -722,8 +674,7 @@ export class ControlHubInternal implements ControlHub { async setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise { await this.sendCommand("setServoPulseWidth", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + id: this.id, servoChannel: servoChannel, pulseWidth: pulseWidth, }); @@ -755,7 +706,7 @@ export class ControlHubInternal implements ControlHub { } async sendCommand(type: string, params: P, timeout: number = 1000): Promise { - let key = 0; + let key = this.keyGenerator++; let messagePayload = { commandKey: key, commandPayload: JSON.stringify(params), @@ -793,11 +744,13 @@ export class ControlHubInternal implements ControlHub { }); } - addChild(hub: RevHub): void { + async addChild(hub: RevHub): Promise { throw new Error("not implemented"); } - addChildByAddress(moduleAddress: number): Promise { - throw new Error("not implemented"); + async addChildByAddress(moduleAddress: number): Promise { + let id: string = await this.sendCommand("addChild", moduleAddress); + + return new ControlHubInternal("(embedded)", id); } } From eb7a35ad0e59293eff8937a9d6803be447e749c5 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 9 Jun 2023 14:55:45 -0500 Subject: [PATCH 033/148] update to latest changes in control hub --- packages/control-hub/src/discovery.ts | 2 +- packages/control-hub/src/index.ts | 3 ++- packages/control-hub/src/internal/ControlHub.ts | 13 +++++++++---- packages/sample/src/adb-setup.ts | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index bb85d757..5a5078d3 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -10,7 +10,7 @@ export async function openConnectedControlHub(): Promise } async function createWiFiControlHub(): Promise { - let hub = new ControlHubInternal("Placeholder"); + let hub = new ControlHubInternal("Placeholder", 173); if (!(await hub.isWiFiConnected())) { throw new Error("Hub is not connected via WiFi"); diff --git a/packages/control-hub/src/index.ts b/packages/control-hub/src/index.ts index 14bf7881..6337ac9d 100644 --- a/packages/control-hub/src/index.ts +++ b/packages/control-hub/src/index.ts @@ -5,9 +5,10 @@ export { openConnectedControlHub } from "./discovery.js"; export async function openControlHub( serialNumber: string, + moduleAddress: number, port: number, ): Promise { - let hub = new ControlHubInternal(serialNumber); + let hub = new ControlHubInternal(serialNumber, moduleAddress); await hub.open("127.0.0.1", (port + 1).toString()); return hub; } diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 6e2440b4..a55dd43b 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -34,7 +34,7 @@ export class ControlHubInternal implements ControlHub { readonly serialNumber: string; readonly children: ReadonlyArray = []; - private id: string | null; + private id: any | null; private keyGenerator = 0; private supportedManualControlMajorVersion = 0; @@ -51,8 +51,9 @@ export class ControlHubInternal implements ControlHub { (response: any | undefined, error: any | undefined) => void >(); - constructor(serialNumber: string, id: string | null = null) { + constructor(serialNumber: string, moduleAddress: number, id: any | null = null) { this.serialNumber = serialNumber; + this.moduleAddress = moduleAddress; this.id = id; } @@ -96,6 +97,10 @@ export class ControlHubInternal implements ControlHub { return new Promise((resolve, reject) => { this.webSocketConnection.on("open", async () => { this.isConnected = true; + this.id = await this.sendCommand("openHub", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }); let apiVersion: { majorVersion: number; minorVersion: number } = await this.sendCommand("start", {}); @@ -749,8 +754,8 @@ export class ControlHubInternal implements ControlHub { } async addChildByAddress(moduleAddress: number): Promise { - let id: string = await this.sendCommand("addChild", moduleAddress); + let id: any = await this.sendCommand("addChild", moduleAddress); - return new ControlHubInternal("(embedded)", id); + return new ControlHubInternal("(embedded)", moduleAddress, id); } } diff --git a/packages/sample/src/adb-setup.ts b/packages/sample/src/adb-setup.ts index 317fe96b..e11583fd 100644 --- a/packages/sample/src/adb-setup.ts +++ b/packages/sample/src/adb-setup.ts @@ -15,7 +15,7 @@ export async function openUsbControlHubs(): Promise { let port = await configureHubTcp(deviceClient); let serialNumber = device.id; - let hub = await openControlHub("(embedded)", port); + let hub = await openControlHub("(embedded)", 173, port); controlHubs.push(hub); } } From 152705668566e1372c742fde7fe91b758f1bfd4f Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 15 Jun 2023 12:27:56 -0500 Subject: [PATCH 034/148] Properly handle children hierarchy on Control Hub --- packages/control-hub/src/discovery.ts | 2 +- packages/control-hub/src/index.ts | 3 +- .../control-hub/src/internal/ControlHub.ts | 556 ++++++--------- .../src/internal/ControlHubConnected.ts | 639 ++++++++++++++++++ packages/core/src/ControlHub.ts | 7 +- packages/core/src/RevHub.ts | 1 - packages/sample/src/HubStringify.ts | 17 +- packages/sample/src/adb-setup.ts | 2 +- packages/sample/src/command/list.ts | 15 +- packages/sample/src/command/servo.ts | 5 +- tsconfig.json | 1 + 11 files changed, 893 insertions(+), 355 deletions(-) create mode 100644 packages/control-hub/src/internal/ControlHubConnected.ts diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index 5a5078d3..bb85d757 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -10,7 +10,7 @@ export async function openConnectedControlHub(): Promise } async function createWiFiControlHub(): Promise { - let hub = new ControlHubInternal("Placeholder", 173); + let hub = new ControlHubInternal("Placeholder"); if (!(await hub.isWiFiConnected())) { throw new Error("Hub is not connected via WiFi"); diff --git a/packages/control-hub/src/index.ts b/packages/control-hub/src/index.ts index 6337ac9d..3ac46878 100644 --- a/packages/control-hub/src/index.ts +++ b/packages/control-hub/src/index.ts @@ -2,13 +2,14 @@ import { ControlHubInternal } from "./internal/ControlHub.js"; import { ControlHub } from "@rev-robotics/rev-hub-core"; export { openConnectedControlHub } from "./discovery.js"; +export { openUsbControlHubsAndChildren } from "./internal/ControlHub.js"; export async function openControlHub( serialNumber: string, moduleAddress: number, port: number, ): Promise { - let hub = new ControlHubInternal(serialNumber, moduleAddress); + let hub = new ControlHubInternal(serialNumber); await hub.open("127.0.0.1", (port + 1).toString()); return hub; } diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index a55dd43b..43360f61 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -1,38 +1,47 @@ +import axios from "axios"; +import semver from "semver"; +import WebSocket from "isomorphic-ws"; import { BulkInputData, + ControlHub, DebugGroup, DioDirection, + ExpansionHub, I2CReadStatus, I2CSpeedCode, I2CWriteStatus, LedPattern, ModuleInterface, ModuleStatus, - PidCoefficients, - Rgb, - VerbosityLevel, - Version, -} from "@rev-robotics/rhsplib"; -import axios from "axios"; -import semver from "semver"; -import WebSocket from "isomorphic-ws"; -import { - ControlHub, - ExpansionHub, ParentRevHub, + PidCoefficients, RevHub, RevHubType, + Rgb, TimeoutError, + VerbosityLevel, + Version, } from "@rev-robotics/rev-hub-core"; +import { openUsbControlHubs } from "rev-hub-cli/dist/adb-setup.js"; import { clearTimeout } from "timers"; +import { ControlHubConnected } from "./ControlHubConnected.js"; export class ControlHubInternal implements ControlHub { readonly isOpen: boolean = true; - moduleAddress: number = 0; + readonly moduleAddress: number = 173; responseTimeoutMs: number = 0; type: RevHubType = RevHubType.ControlHub; readonly serialNumber: string; - readonly children: ReadonlyArray = []; + + /** + * All children connected over USB, as well as the one embedded hub. + */ + readonly children: RevHub[] = []; + + /** + * All children connected over USB. + */ + readonly usbChildren: RevHub[] = []; private id: any | null; private keyGenerator = 0; @@ -45,16 +54,20 @@ export class ControlHubInternal implements ControlHub { */ isConnected = false; + /** + * The board for this control hub. All Expansion Hub commands go through + * this delegate. + */ + private embedded!: ControlHubConnected; + private webSocketConnection!: WebSocket; private currentActiveCommands = new Map< any, (response: any | undefined, error: any | undefined) => void >(); - constructor(serialNumber: string, moduleAddress: number, id: any | null = null) { + constructor(serialNumber: string) { this.serialNumber = serialNumber; - this.moduleAddress = moduleAddress; - this.id = id; } isParent(): this is ParentRevHub { @@ -97,26 +110,34 @@ export class ControlHubInternal implements ControlHub { return new Promise((resolve, reject) => { this.webSocketConnection.on("open", async () => { this.isConnected = true; - this.id = await this.sendCommand("openHub", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, - }); + await this.subscribe(); let apiVersion: { majorVersion: number; minorVersion: number } = await this.sendCommand("start", {}); + this.id = await this.openHub("(embedded)", this.moduleAddress); + + this.embedded = new ControlHubConnected( + true, + RevHubType.ControlHub, + this.sendCommand, + "(embedded)", + this.moduleAddress, + this.id, + ); + + this.children.push(this.embedded); + if ( - apiVersion.majorVersion != this.supportedManualControlMajorVersion || + apiVersion.majorVersion !== this.supportedManualControlMajorVersion || apiVersion.minorVersion < this.supportedManualControlMinorVersion ) { - throw new Error( - `API Version ${apiVersion.majorVersion}.${apiVersion.minorVersion} is not supported`, + reject( + new Error( + `API Version ${apiVersion.majorVersion}.${apiVersion.minorVersion} is not supported`, + ), ); } - this.moduleAddress = await this.sendCommand("getModuleAddress", { - serialNumber: "(embedded)", - moduleAddress: 173, - }); resolve(); }); }); @@ -142,275 +163,180 @@ export class ControlHubInternal implements ControlHub { return path.includes("_box") && path.includes("msm8916_64"); } - close(): void { - this.sendCommand("stop", {}).then(() => { - this.webSocketConnection.close(); + async subscribe(): Promise { + let payload = { + namespace: "system", + type: "subscribeToNamespace", + payload: "MC", + }; + this.webSocketConnection.send(JSON.stringify(payload)); + } + + async openHub( + serialNumber: string, + parentAddress: number, + address: number = parentAddress, + ): Promise { + return await this.sendCommand("openHub", { + parentSerialNumber: serialNumber, + parentHubAddress: parentAddress, + hubAddress: address, }); } + close() { + this.embedded.close(); + this.webSocketConnection.close(); + } + async getAnalogInput(channel: number): Promise { - return await this.sendCommand("getAnalogInput", { - id: this.id, - channel: channel, - }); + return this.embedded.getAnalogInput(channel); } async get5VBusVoltage(): Promise { - return await this.sendCommand("get5VBusVoltage", { - id: this.id, - }); + return this.embedded.get5VBusVoltage(); } async getBatteryCurrent(): Promise { - return await this.sendCommand("getBatteryCurrent", { - id: this.id, - }); + return this.embedded.getBatteryCurrent(); } async getBatteryVoltage(): Promise { - return await this.sendCommand("getBatteryVoltage", { - id: this.id, - }); + return this.embedded.getBatteryVoltage(); } async getDigitalBusCurrent(): Promise { - return await this.sendCommand("getDigitalBusCurrent", { - id: this.id, - }); + return this.embedded.getDigitalBusCurrent(); } async getI2CCurrent(): Promise { - return await this.sendCommand("getI2CCurrent", { - id: this.id, - }); + return this.embedded.getI2CCurrent(); } async getMotorCurrent(motorChannel: number): Promise { - return await this.sendCommand("getMotorCurrent", { - id: this.id, - }); + return this.embedded.getMotorCurrent(motorChannel); } async getServoCurrent(): Promise { - return await this.sendCommand("getMotorCurrent", { - id: this.id, - }); + return this.embedded.getServoCurrent(); } async getTemperature(): Promise { - return await this.sendCommand("getTemperature", { - id: this.id, - }); + return this.embedded.getTemperature(); } async getBulkInputData(): Promise { - return await this.sendCommand("getBulkInputData", { - id: this.id, - }); + return this.embedded.getBulkInputData(); } async getDigitalAllInputs(): Promise { - return await this.sendCommand("getAllDigitalInputs", { - id: this.id, - }); + return this.embedded.getDigitalAllInputs(); } async getDigitalDirection(dioPin: number): Promise { - let isOutput = await this.sendCommand("getDigitalDirection", { - id: this.id, - channel: dioPin, - }); - - return isOutput ? DioDirection.Output : DioDirection.Input; + return this.embedded.getDigitalDirection(dioPin); } async getDigitalSingleInput(dioPin: number): Promise { - return await this.sendCommand("getDigitalInput", { - id: this.id, - channel: dioPin, - }); + return this.embedded.getDigitalSingleInput(dioPin); } async getFTDIResetControl(): Promise { - return await this.sendCommand("getFtdiResetControl", { - id: this.id, - }); + return this.embedded.getFTDIResetControl(); } async getI2CChannelConfiguration(i2cChannel: number): Promise { - let speedCode = await this.sendCommand("getI2CChannelConfiguration", { - id: this.id, - channel: i2cChannel, - }); - - return speedCode == 1 - ? I2CSpeedCode.SpeedCode400_Kbps - : I2CSpeedCode.SpeedCode100_Kbps; + return this.embedded.getI2CChannelConfiguration(i2cChannel); } getI2CReadStatus(i2cChannel: number): Promise { - throw new Error("not implemented"); + return this.embedded.getI2CReadStatus(i2cChannel); } getI2CWriteStatus(i2cChannel: number): Promise { - throw new Error("not implemented"); + return this.embedded.getI2CWriteStatus(i2cChannel); } async getInterfacePacketID( interfaceName: string, functionNumber: number, ): Promise { - return await this.sendCommand("getInterfacePacketId", { - id: this.id, - interfaceName: interfaceName, - functionNumber: functionNumber, - }); + return this.embedded.getInterfacePacketID(interfaceName, functionNumber); } async getModuleLedColor(): Promise { - let result: { r: number; g: number; b: number } = await this.sendCommand( - "getLedColor", - { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, - }, - ); - - return { - red: result.r, - green: result.g, - blue: result.b, - }; + return this.embedded.getModuleLedColor(); } getModuleLedPattern(): Promise { - throw new Error("not implemented"); + return this.embedded.getModuleLedPattern(); } async getModuleStatus(clearStatusAfterResponse: boolean): Promise { - return await this.sendCommand("getModuleStatus", { - id: this.id, - }); + return this.embedded.getModuleStatus(clearStatusAfterResponse); } async getMotorAtTarget(motorChannel: number): Promise { - return await this.sendCommand("getIsMotorAtTarget", { - id: this.id, - }); + return this.embedded.getMotorAtTarget(motorChannel); } async getMotorChannelCurrentAlertLevel(motorChannel: number): Promise { - return await this.sendCommand("getMotorAlertLevel", { - id: this.id, - motorChannel: motorChannel, - }); + return this.embedded.getMotorChannelCurrentAlertLevel(motorChannel); } async getMotorChannelEnable(motorChannel: number): Promise { - return await this.sendCommand("getMotorChannelEnable", { - id: this.id, - motorChannel: motorChannel, - }); + return this.embedded.getMotorChannelEnable(motorChannel); } async getMotorChannelMode( motorChannel: number, ): Promise<{ motorMode: number; floatAtZero: boolean }> { - return await this.sendCommand("getMotorMode", { - id: this.id, - motorChannel: motorChannel, - }); + return this.embedded.getMotorChannelMode(motorChannel); } async getMotorConstantPower(motorChannel: number): Promise { - return await this.sendCommand("getMotorConstantPower", { - id: this.id, - motorChannel: motorChannel, - }); + return this.embedded.getMotorConstantPower(motorChannel); } async getMotorEncoderPosition(motorChannel: number): Promise { - return await this.sendCommand("getMotorEncoderPosition", { - id: this.id, - motorChannel: motorChannel, - }); + return this.embedded.getMotorEncoderPosition(motorChannel); } async getMotorPIDCoefficients( motorChannel: number, motorMode: number, ): Promise { - let result: { p: number; i: number; d: number } = await this.sendCommand( - "getMotorPidCoefficients", - { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, - motorChannel: motorChannel, - }, - ); - - return { - p: result.p, - i: result.i, - d: result.d, - }; + return this.embedded.getMotorPIDCoefficients(motorChannel, motorMode); } async getMotorTargetPosition( motorChannel: number, ): Promise<{ targetPosition: number; targetTolerance: number }> { - let result: { targetPositionCounts: number; targetToleranceCounts: number } = - await this.sendCommand("getMotorTargetPosition", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, - motorChannel: motorChannel, - }); - - return { - targetPosition: result.targetPositionCounts, - targetTolerance: result.targetToleranceCounts, - }; + return this.embedded.getMotorTargetPosition(motorChannel); } async getMotorTargetVelocity(motorChannel: number): Promise { - return await this.sendCommand("getMotorTargetVelocity", { - id: this.id, - motorChannel: motorChannel, - }); + return this.embedded.getMotorTargetVelocity(motorChannel); } async getPhoneChargeControl(): Promise { - return await this.sendCommand("getPhoneChargeControl", { - id: this.id, - }); + return this.embedded.getPhoneChargeControl(); } async getServoConfiguration(servoChannel: number): Promise { - return await this.sendCommand("getServoConfiguration", { - id: this.id, - servoChannel: servoChannel, - }); + return this.embedded.getServoConfiguration(servoChannel); } async getServoEnable(servoChannel: number): Promise { - return await this.sendCommand("getServoEnable", { - id: this.id, - servoChannel: servoChannel, - }); + return this.embedded.getServoEnable(servoChannel); } async getServoPulseWidth(servoChannel: number): Promise { - return await this.sendCommand("getServoPulseWidth", { - id: this.id, - servoChannel: servoChannel, - }); + return this.embedded.getServoPulseWidth(servoChannel); } async injectDataLogHint(hintText: string): Promise { - await this.sendCommand("injectDebugLogHint", { - id: this.id, - hint: hintText, - }); + return this.embedded.injectDataLogHint(hintText); } isExpansionHub(): this is ExpansionHub { @@ -418,22 +344,11 @@ export class ControlHubInternal implements ControlHub { } on(eventName: "error", listener: (error: Error) => void): RevHub { - throw new Error("not implemented"); + return this.embedded.on(eventName, listener); } async queryInterface(interfaceName: string): Promise { - let result: { name: string; firstPacketId: number; numberIds: number } = - await this.sendCommand("queryInterface", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, - interfaceName: interfaceName, - }); - - return { - name: result.name, - firstPacketID: result.firstPacketId, - numberIDValues: result.numberIds, - }; + return this.embedded.queryInterface(interfaceName); } readI2CMultipleBytes( @@ -441,147 +356,95 @@ export class ControlHubInternal implements ControlHub { slaveAddress: number, numBytesToRead: number, ): Promise { - throw new Error("not implemented"); + return this.embedded.readI2CMultipleBytes( + i2cChannel, + slaveAddress, + numBytesToRead, + ); } readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise { - throw new Error("not implemented"); + return this.embedded.readI2CSingleByte(i2cChannel, slaveAddress); } async readVersion(): Promise { - let versionString = await this.readVersionString(); - //ToDo(landry) parse version string - throw new Error("not implemented"); + return this.embedded.readVersion(); } async readVersionString(): Promise { - return await this.sendCommand("readVersionString", { - id: this.id, - }); + return this.embedded.readVersionString(); } async resetMotorEncoder(motorChannel: number): Promise { - await this.sendCommand("resetMotorEncoder", { - id: this.id, - motorChannel: motorChannel, - }); + return this.embedded.resetMotorEncoder(motorChannel); } async sendFailSafe(): Promise { - await this.sendCommand("readVersionString", { - id: this.id, - }); + return this.embedded.sendFailSafe(); } - async sendKeepAlive(): Promise {} + async sendKeepAlive(): Promise { + return this.embedded.sendKeepAlive(); + } async sendReadCommand(packetTypeID: number, payload: number[]): Promise { - return Promise.resolve([]); + return this.embedded.sendReadCommand(packetTypeID, payload); } sendWriteCommand(packetTypeID: number, payload: number[]): Promise { - return Promise.resolve([]); + return this.embedded.sendWriteCommand(packetTypeID, payload); } async setDebugLogLevel( debugGroup: DebugGroup, verbosityLevel: VerbosityLevel, ): Promise { - await this.sendCommand("readVersionString", { - id: this.id, - debugGroup: debugGroup, - verbosityLevel: verbosityLevel, - }); + return this.embedded.setDebugLogLevel(debugGroup, verbosityLevel); } async setDigitalAllOutputs(bitPackedField: number): Promise { - await this.sendCommand("readVersionString", { - id: this.id, - bitField: bitPackedField, - }); + return this.embedded.setDigitalAllOutputs(bitPackedField); } async setDigitalDirection(dioPin: number, direction: DioDirection): Promise { - await this.sendCommand("readVersionString", { - id: this.id, - pin: dioPin, - isOutput: direction == DioDirection.Output, - }); + return this.embedded.setDigitalDirection(dioPin, direction); } async setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { - await this.sendCommand("readVersionString", { - id: this.id, - pin: dioPin, - value: value ?? false, - }); + return this.embedded.setDigitalSingleOutput(dioPin, value); } async setFTDIResetControl(ftdiResetControl: boolean): Promise { - await this.sendCommand("setFtdiResetControl", { - id: this.id, - }); + return this.embedded.setFTDIResetControl(ftdiResetControl); } async setI2CChannelConfiguration( i2cChannel: number, speedCode: I2CSpeedCode, ): Promise { - await this.sendCommand("setI2CChannelConfiguration", { - id: this.id, - i2cChannel: i2cChannel, - speedCode: speedCode, - }); + return this.embedded.setI2CChannelConfiguration(i2cChannel, speedCode); } async setModuleLedColor(red: number, green: number, blue: number): Promise { - await this.sendCommand("setLedColor", { - id: this.id, - r: red, - g: green, - b: blue, - }); + return this.embedded.setModuleLedColor(red, green, blue); } async setModuleLedPattern(ledPattern: LedPattern): Promise { - await this.sendCommand("setLedPattern", { - id: this.id, - rgbtPatternStep0: ledPattern.rgbtPatternStep0, - rgbtPatternStep1: ledPattern.rgbtPatternStep1, - rgbtPatternStep2: ledPattern.rgbtPatternStep2, - rgbtPatternStep3: ledPattern.rgbtPatternStep3, - rgbtPatternStep4: ledPattern.rgbtPatternStep4, - rgbtPatternStep5: ledPattern.rgbtPatternStep5, - rgbtPatternStep6: ledPattern.rgbtPatternStep6, - rgbtPatternStep7: ledPattern.rgbtPatternStep7, - rgbtPatternStep8: ledPattern.rgbtPatternStep8, - rgbtPatternStep9: ledPattern.rgbtPatternStep9, - rgbtPatternStep10: ledPattern.rgbtPatternStep10, - rgbtPatternStep11: ledPattern.rgbtPatternStep11, - rgbtPatternStep12: ledPattern.rgbtPatternStep12, - rgbtPatternStep13: ledPattern.rgbtPatternStep13, - rgbtPatternStep14: ledPattern.rgbtPatternStep14, - rgbtPatternStep15: ledPattern.rgbtPatternStep15, - }); + return this.embedded.setModuleLedPattern(ledPattern); } async setMotorChannelCurrentAlertLevel( motorChannel: number, currentLimit_mA: number, ): Promise { - await this.sendCommand("setMotorAlertLevel", { - id: this.id, - motorChannel: motorChannel, - currentLimit_mA: currentLimit_mA, - }); + return this.embedded.setMotorChannelCurrentAlertLevel( + motorChannel, + currentLimit_mA, + ); } async setMotorChannelEnable(motorChannel: number, enable: boolean): Promise { - await this.sendCommand("setMotorEnabled", { - id: this.id, - motorChannel: motorChannel, - enable: enable, - }); + return this.embedded.setMotorChannelEnable(motorChannel, enable); } async setMotorChannelMode( @@ -589,20 +452,11 @@ export class ControlHubInternal implements ControlHub { motorMode: number, floatAtZero: boolean, ): Promise { - await this.sendCommand("setMotorChannelMode", { - id: this.id, - motorChannel: motorChannel, - motorMode: motorMode, - floatAtZero: floatAtZero, - }); + return this.embedded.setMotorChannelMode(motorChannel, motorMode, floatAtZero); } async setMotorConstantPower(motorChannel: number, powerLevel: number): Promise { - await this.sendCommand("setMotorConstantPower", { - id: this.id, - motorChannel: motorChannel, - motorPower: powerLevel, - }); + return this.embedded.setMotorConstantPower(motorChannel, powerLevel); } async setMotorPIDCoefficients( @@ -610,14 +464,7 @@ export class ControlHubInternal implements ControlHub { motorMode: number, pid: PidCoefficients, ): Promise { - await this.sendCommand("setMotorPidCoefficients", { - id: this.id, - motorChannel: motorChannel, - motorMode: motorMode, - p: pid.p, - i: pid.i, - d: pid.d, - }); + return this.embedded.setMotorPIDCoefficients(motorChannel, motorMode, pid); } async setMotorTargetPosition( @@ -625,64 +472,41 @@ export class ControlHubInternal implements ControlHub { targetPosition_counts: number, targetTolerance_counts: number, ): Promise { - await this.sendCommand("setMotorTargetPosition", { - id: this.id, - motorChannel: motorChannel, - targetPositionCounts: targetPosition_counts, - targetToleranceCounts: targetTolerance_counts, - }); + return this.embedded.setMotorTargetPosition( + motorChannel, + targetPosition_counts, + targetTolerance_counts, + ); } async setMotorTargetVelocity( motorChannel: number, velocity_cps: number, ): Promise { - await this.sendCommand("setMotorTargetVelocity", { - id: this.id, - motorChannel: motorChannel, - velocityCps: velocity_cps, - }); + return this.embedded.setMotorTargetVelocity(motorChannel, velocity_cps); } async setNewModuleAddress(newModuleAddress: number): Promise { - await this.sendCommand("setNewModuleAddress", { - id: this.id, - address: newModuleAddress, - }); + return this.embedded.setNewModuleAddress(newModuleAddress); } async setPhoneChargeControl(chargeEnable: boolean): Promise { - await this.sendCommand("setPhoneChargeControl", { - id: this.id, - enabled: chargeEnable, - }); + return this.embedded.setPhoneChargeControl(chargeEnable); } async setServoConfiguration( servoChannel: number, framePeriod: number, ): Promise { - await this.sendCommand("setServoConfiguration", { - id: this.id, - servoChannel: servoChannel, - framePeriod: framePeriod, - }); + return this.embedded.setServoConfiguration(servoChannel, framePeriod); } async setServoEnable(servoChannel: number, enable: boolean): Promise { - await this.sendCommand("setServoEnable", { - id: this.id, - servoChannel: servoChannel, - enabled: enable, - }); + return this.embedded.setServoEnable(servoChannel, enable); } async setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise { - await this.sendCommand("setServoPulseWidth", { - id: this.id, - servoChannel: servoChannel, - pulseWidth: pulseWidth, - }); + return this.embedded.setServoPulseWidth(servoChannel, pulseWidth); } writeI2CMultipleBytes( @@ -690,7 +514,7 @@ export class ControlHubInternal implements ControlHub { slaveAddress: number, bytes: number[], ): Promise { - throw new Error("not implemented"); + return this.embedded.writeI2CMultipleBytes(i2cChannel, slaveAddress, bytes); } writeI2CReadMultipleBytes( @@ -699,7 +523,12 @@ export class ControlHubInternal implements ControlHub { numBytesToRead: number, startAddress: number, ): Promise { - throw new Error("not implemented"); + return this.embedded.writeI2CReadMultipleBytes( + i2cChannel, + slaveAddress, + numBytesToRead, + startAddress, + ); } writeI2CSingleByte( @@ -707,9 +536,41 @@ export class ControlHubInternal implements ControlHub { slaveAddress: number, byte: number, ): Promise { + return this.embedded.writeI2CSingleByte(i2cChannel, slaveAddress, byte); + } + + async addChild(hub: RevHub): Promise { throw new Error("not implemented"); } + async addChildByAddress(moduleAddress: number): Promise { + return this.addHubBySerialNumberAndAddress(this.serialNumber, moduleAddress); + } + + async addHubBySerialNumberAndAddress( + serialNumber: string, + moduleAddress: number, + ): Promise { + let id: any = this.openHub(serialNumber, moduleAddress, moduleAddress); + + let newHub = new ControlHubConnected( + true, + RevHubType.ExpansionHub, + this.sendCommand.bind(this), + serialNumber, + moduleAddress, + id, + ); + + this.usbChildren.push(newHub); + this.children.push(newHub); + + if (!newHub.isParentHub) { + throw new Error("A child hub with a serial number must also be a parent."); + } + return newHub; + } + async sendCommand(type: string, params: P, timeout: number = 1000): Promise { let key = this.keyGenerator++; let messagePayload = { @@ -722,7 +583,7 @@ export class ControlHubInternal implements ControlHub { payload: JSON.stringify(messagePayload), }; - this.webSocketConnection?.send(JSON.stringify(payload)); + this.webSocketConnection.send(JSON.stringify(payload)); let callbackPromise: Promise = new Promise((resolve, reject) => { this.currentActiveCommands.set(key, (response, error) => { @@ -740,6 +601,7 @@ export class ControlHubInternal implements ControlHub { let timer!: NodeJS.Timer; let timeoutPromise: Promise = new Promise((_, reject) => { timer = setTimeout(() => { + console.log(`Got timeout for ${type}`); reject(new TimeoutError()); }, timeout); }); @@ -748,14 +610,38 @@ export class ControlHubInternal implements ControlHub { clearTimeout(timer); }); } +} - async addChild(hub: RevHub): Promise { - throw new Error("not implemented"); - } +export async function openUsbControlHubsAndChildren(): Promise { + let hubs = await openUsbControlHubs(); + let result: ControlHub[] = []; - async addChildByAddress(moduleAddress: number): Promise { - let id: any = await this.sendCommand("addChild", moduleAddress); + for (let hub of hubs) { + let controlHub = hub as ControlHubInternal; + let addresses: Record< + string, + { + serialNumber: string; + parentHubAddress: number; + childAddresses: number[]; + } + > = await controlHub.sendCommand("scanAndDiscover", {}, 20000); + + for (let serialNumber in addresses) { + if (serialNumber === "(embedded)") continue; - return new ControlHubInternal("(embedded)", moduleAddress, id); + let parentHubInfo = addresses[serialNumber]; + let parentHub = await controlHub.addHubBySerialNumberAndAddress( + serialNumber, + parentHubInfo.parentHubAddress, + ); + + for (let childAddress of parentHubInfo.childAddresses) { + await parentHub.addChildByAddress(childAddress); + } + } + result.push(controlHub); } + + return result; } diff --git a/packages/control-hub/src/internal/ControlHubConnected.ts b/packages/control-hub/src/internal/ControlHubConnected.ts new file mode 100644 index 00000000..aa0c5cf7 --- /dev/null +++ b/packages/control-hub/src/internal/ControlHubConnected.ts @@ -0,0 +1,639 @@ +import { + BulkInputData, + DebugGroup, + DioDirection, + ExpansionHub, + I2CReadStatus, + I2CSpeedCode, + I2CWriteStatus, + LedPattern, + ModuleInterface, + ModuleStatus, + ParentExpansionHub, + ParentRevHub, + PidCoefficients, + RevHub, + RevHubType, + Rgb, + VerbosityLevel, + Version, +} from "@rev-robotics/rev-hub-core"; + +export class ControlHubConnected implements ParentExpansionHub { + isParentHub: boolean; + type: RevHubType; + id: any; + serialNumber: string; + moduleAddress: number; + sendCommand: (name: string, params: P, timeout?: number) => Promise; + + isOpen: boolean = false; + + responseTimeoutMs = 1000; + + readonly children: RevHub[] = []; + + constructor( + isParent: boolean, + type: RevHubType, + sendCommand: (name: string, params: P, timeout?: number) => Promise, + serialNumber: string, + moduleAddress: number, + id: any, + ) { + this.isParentHub = isParent; + this.type = type; + this.id = id; + this.serialNumber = serialNumber; + this.moduleAddress = moduleAddress; + this.sendCommand = sendCommand; + } + + isParent(): this is ParentRevHub { + return this.isParentHub; + } + + close(): void {} + + async getAnalogInput(channel: number): Promise { + return await this.sendCommand("getAnalogInput", { + id: this.id, + channel: channel, + }); + } + + async get5VBusVoltage(): Promise { + return await this.sendCommand("get5VBusVoltage", { + id: this.id, + }); + } + + async getBatteryCurrent(): Promise { + return await this.sendCommand("getBatteryCurrent", { + id: this.id, + }); + } + + async getBatteryVoltage(): Promise { + return await this.sendCommand("getBatteryVoltage", { + id: this.id, + }); + } + + async getDigitalBusCurrent(): Promise { + return await this.sendCommand("getDigitalBusCurrent", { + id: this.id, + }); + } + + async getI2CCurrent(): Promise { + return await this.sendCommand("getI2CCurrent", { + id: this.id, + }); + } + + async getMotorCurrent(motorChannel: number): Promise { + return await this.sendCommand("getMotorCurrent", { + id: this.id, + }); + } + + async getServoCurrent(): Promise { + return await this.sendCommand("getMotorCurrent", { + id: this.id, + }); + } + + async getTemperature(): Promise { + return await this.sendCommand("getTemperature", { + id: this.id, + }); + } + + async getBulkInputData(): Promise { + return await this.sendCommand("getBulkInputData", { + id: this.id, + }); + } + + async getDigitalAllInputs(): Promise { + return await this.sendCommand("getAllDigitalInputs", { + id: this.id, + }); + } + + async getDigitalDirection(dioPin: number): Promise { + let isOutput = await this.sendCommand("getDigitalDirection", { + id: this.id, + channel: dioPin, + }); + + return isOutput ? DioDirection.Output : DioDirection.Input; + } + + async getDigitalSingleInput(dioPin: number): Promise { + return await this.sendCommand("getDigitalInput", { + id: this.id, + channel: dioPin, + }); + } + + async getFTDIResetControl(): Promise { + return await this.sendCommand("getFtdiResetControl", { + id: this.id, + }); + } + + async getI2CChannelConfiguration(i2cChannel: number): Promise { + let speedCode = await this.sendCommand("getI2CChannelConfiguration", { + id: this.id, + channel: i2cChannel, + }); + + return speedCode == 1 + ? I2CSpeedCode.SpeedCode400_Kbps + : I2CSpeedCode.SpeedCode100_Kbps; + } + + getI2CReadStatus(i2cChannel: number): Promise { + throw new Error("not implemented"); + } + + getI2CWriteStatus(i2cChannel: number): Promise { + throw new Error("not implemented"); + } + + async getInterfacePacketID( + interfaceName: string, + functionNumber: number, + ): Promise { + return await this.sendCommand("getInterfacePacketId", { + id: this.id, + interfaceName: interfaceName, + functionNumber: functionNumber, + }); + } + + async getModuleLedColor(): Promise { + let result: { r: number; g: number; b: number } = await this.sendCommand( + "getLedColor", + { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + }, + ); + + return { + red: result.r, + green: result.g, + blue: result.b, + }; + } + + getModuleLedPattern(): Promise { + throw new Error("not implemented"); + } + + async getModuleStatus(clearStatusAfterResponse: boolean): Promise { + return await this.sendCommand("getModuleStatus", { + id: this.id, + }); + } + + async getMotorAtTarget(motorChannel: number): Promise { + return await this.sendCommand("getIsMotorAtTarget", { + id: this.id, + }); + } + + async getMotorChannelCurrentAlertLevel(motorChannel: number): Promise { + return await this.sendCommand("getMotorAlertLevel", { + id: this.id, + motorChannel: motorChannel, + }); + } + + async getMotorChannelEnable(motorChannel: number): Promise { + return await this.sendCommand("getMotorChannelEnable", { + id: this.id, + motorChannel: motorChannel, + }); + } + + async getMotorChannelMode( + motorChannel: number, + ): Promise<{ motorMode: number; floatAtZero: boolean }> { + return await this.sendCommand("getMotorMode", { + id: this.id, + motorChannel: motorChannel, + }); + } + + async getMotorConstantPower(motorChannel: number): Promise { + return await this.sendCommand("getMotorConstantPower", { + id: this.id, + motorChannel: motorChannel, + }); + } + + async getMotorEncoderPosition(motorChannel: number): Promise { + return await this.sendCommand("getMotorEncoderPosition", { + id: this.id, + motorChannel: motorChannel, + }); + } + + async getMotorPIDCoefficients( + motorChannel: number, + motorMode: number, + ): Promise { + let result: { p: number; i: number; d: number } = await this.sendCommand( + "getMotorPidCoefficients", + { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }, + ); + + return { + p: result.p, + i: result.i, + d: result.d, + }; + } + + async getMotorTargetPosition( + motorChannel: number, + ): Promise<{ targetPosition: number; targetTolerance: number }> { + let result: { targetPositionCounts: number; targetToleranceCounts: number } = + await this.sendCommand("getMotorTargetPosition", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + motorChannel: motorChannel, + }); + + return { + targetPosition: result.targetPositionCounts, + targetTolerance: result.targetToleranceCounts, + }; + } + + async getMotorTargetVelocity(motorChannel: number): Promise { + return await this.sendCommand("getMotorTargetVelocity", { + id: this.id, + motorChannel: motorChannel, + }); + } + + async getPhoneChargeControl(): Promise { + return await this.sendCommand("getPhoneChargeControl", { + id: this.id, + }); + } + + async getServoConfiguration(servoChannel: number): Promise { + return await this.sendCommand("getServoConfiguration", { + id: this.id, + servoChannel: servoChannel, + }); + } + + async getServoEnable(servoChannel: number): Promise { + return await this.sendCommand("getServoEnable", { + id: this.id, + servoChannel: servoChannel, + }); + } + + async getServoPulseWidth(servoChannel: number): Promise { + return await this.sendCommand("getServoPulseWidth", { + id: this.id, + servoChannel: servoChannel, + }); + } + + async injectDataLogHint(hintText: string): Promise { + await this.sendCommand("injectDebugLogHint", { + id: this.id, + hint: hintText, + }); + } + + isExpansionHub(): this is ExpansionHub { + return true; + } + + on(eventName: "error", listener: (error: Error) => void): RevHub { + throw new Error("not implemented"); + } + + async queryInterface(interfaceName: string): Promise { + let result: { name: string; firstPacketId: number; numberIds: number } = + await this.sendCommand("queryInterface", { + serialNumber: this.serialNumber, + moduleAddress: this.moduleAddress, + interfaceName: interfaceName, + }); + + return { + name: result.name, + firstPacketID: result.firstPacketId, + numberIDValues: result.numberIds, + }; + } + + readI2CMultipleBytes( + i2cChannel: number, + slaveAddress: number, + numBytesToRead: number, + ): Promise { + throw new Error("not implemented"); + } + + readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise { + throw new Error("not implemented"); + } + + async readVersion(): Promise { + let versionString = await this.readVersionString(); + //ToDo(landry) parse version string + throw new Error("not implemented"); + } + + async readVersionString(): Promise { + return await this.sendCommand("readVersionString", { + id: this.id, + }); + } + + async resetMotorEncoder(motorChannel: number): Promise { + await this.sendCommand("resetMotorEncoder", { + id: this.id, + motorChannel: motorChannel, + }); + } + + async sendFailSafe(): Promise { + await this.sendCommand("readVersionString", { + id: this.id, + }); + } + + async sendKeepAlive(): Promise {} + + async sendReadCommand(packetTypeID: number, payload: number[]): Promise { + return Promise.resolve([]); + } + + sendWriteCommand(packetTypeID: number, payload: number[]): Promise { + return Promise.resolve([]); + } + + async setDebugLogLevel( + debugGroup: DebugGroup, + verbosityLevel: VerbosityLevel, + ): Promise { + await this.sendCommand("readVersionString", { + id: this.id, + debugGroup: debugGroup, + verbosityLevel: verbosityLevel, + }); + } + + async setDigitalAllOutputs(bitPackedField: number): Promise { + await this.sendCommand("readVersionString", { + id: this.id, + bitField: bitPackedField, + }); + } + + async setDigitalDirection(dioPin: number, direction: DioDirection): Promise { + await this.sendCommand("readVersionString", { + id: this.id, + pin: dioPin, + isOutput: direction == DioDirection.Output, + }); + } + + async setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { + await this.sendCommand("readVersionString", { + id: this.id, + pin: dioPin, + value: value ?? false, + }); + } + + async setFTDIResetControl(ftdiResetControl: boolean): Promise { + await this.sendCommand("setFtdiResetControl", { + id: this.id, + }); + } + + async setI2CChannelConfiguration( + i2cChannel: number, + speedCode: I2CSpeedCode, + ): Promise { + await this.sendCommand("setI2CChannelConfiguration", { + id: this.id, + i2cChannel: i2cChannel, + speedCode: speedCode, + }); + } + + async setModuleLedColor(red: number, green: number, blue: number): Promise { + await this.sendCommand("setLedColor", { + id: this.id, + r: red, + g: green, + b: blue, + }); + } + + async setModuleLedPattern(ledPattern: LedPattern): Promise { + await this.sendCommand("setLedPattern", { + id: this.id, + rgbtPatternStep0: ledPattern.rgbtPatternStep0, + rgbtPatternStep1: ledPattern.rgbtPatternStep1, + rgbtPatternStep2: ledPattern.rgbtPatternStep2, + rgbtPatternStep3: ledPattern.rgbtPatternStep3, + rgbtPatternStep4: ledPattern.rgbtPatternStep4, + rgbtPatternStep5: ledPattern.rgbtPatternStep5, + rgbtPatternStep6: ledPattern.rgbtPatternStep6, + rgbtPatternStep7: ledPattern.rgbtPatternStep7, + rgbtPatternStep8: ledPattern.rgbtPatternStep8, + rgbtPatternStep9: ledPattern.rgbtPatternStep9, + rgbtPatternStep10: ledPattern.rgbtPatternStep10, + rgbtPatternStep11: ledPattern.rgbtPatternStep11, + rgbtPatternStep12: ledPattern.rgbtPatternStep12, + rgbtPatternStep13: ledPattern.rgbtPatternStep13, + rgbtPatternStep14: ledPattern.rgbtPatternStep14, + rgbtPatternStep15: ledPattern.rgbtPatternStep15, + }); + } + + async setMotorChannelCurrentAlertLevel( + motorChannel: number, + currentLimit_mA: number, + ): Promise { + await this.sendCommand("setMotorAlertLevel", { + id: this.id, + motorChannel: motorChannel, + currentLimit_mA: currentLimit_mA, + }); + } + + async setMotorChannelEnable(motorChannel: number, enable: boolean): Promise { + await this.sendCommand("setMotorEnabled", { + id: this.id, + motorChannel: motorChannel, + enable: enable, + }); + } + + async setMotorChannelMode( + motorChannel: number, + motorMode: number, + floatAtZero: boolean, + ): Promise { + await this.sendCommand("setMotorChannelMode", { + id: this.id, + motorChannel: motorChannel, + motorMode: motorMode, + floatAtZero: floatAtZero, + }); + } + + async setMotorConstantPower(motorChannel: number, powerLevel: number): Promise { + await this.sendCommand("setMotorConstantPower", { + id: this.id, + motorChannel: motorChannel, + motorPower: powerLevel, + }); + } + + async setMotorPIDCoefficients( + motorChannel: number, + motorMode: number, + pid: PidCoefficients, + ): Promise { + await this.sendCommand("setMotorPidCoefficients", { + id: this.id, + motorChannel: motorChannel, + motorMode: motorMode, + p: pid.p, + i: pid.i, + d: pid.d, + }); + } + + async setMotorTargetPosition( + motorChannel: number, + targetPosition_counts: number, + targetTolerance_counts: number, + ): Promise { + await this.sendCommand("setMotorTargetPosition", { + id: this.id, + motorChannel: motorChannel, + targetPositionCounts: targetPosition_counts, + targetToleranceCounts: targetTolerance_counts, + }); + } + + async setMotorTargetVelocity( + motorChannel: number, + velocity_cps: number, + ): Promise { + await this.sendCommand("setMotorTargetVelocity", { + id: this.id, + motorChannel: motorChannel, + velocityCps: velocity_cps, + }); + } + + async setNewModuleAddress(newModuleAddress: number): Promise { + await this.sendCommand("setNewModuleAddress", { + id: this.id, + address: newModuleAddress, + }); + } + + async setPhoneChargeControl(chargeEnable: boolean): Promise { + await this.sendCommand("setPhoneChargeControl", { + id: this.id, + enabled: chargeEnable, + }); + } + + async setServoConfiguration( + servoChannel: number, + framePeriod: number, + ): Promise { + await this.sendCommand("setServoConfiguration", { + id: this.id, + servoChannel: servoChannel, + framePeriod: framePeriod, + }); + } + + async setServoEnable(servoChannel: number, enable: boolean): Promise { + await this.sendCommand("setServoEnable", { + id: this.id, + servoChannel: servoChannel, + enabled: enable, + }); + } + + async setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise { + await this.sendCommand("setServoPulseWidth", { + id: this.id, + servoChannel: servoChannel, + pulseWidth: pulseWidth, + }); + } + + writeI2CMultipleBytes( + i2cChannel: number, + slaveAddress: number, + bytes: number[], + ): Promise { + throw new Error("not implemented"); + } + + writeI2CReadMultipleBytes( + i2cChannel: number, + slaveAddress: number, + numBytesToRead: number, + startAddress: number, + ): Promise { + throw new Error("not implemented"); + } + + writeI2CSingleByte( + i2cChannel: number, + slaveAddress: number, + byte: number, + ): Promise { + throw new Error("not implemented"); + } + + async addChildByAddress(moduleAddress: number): Promise { + let id = await this.sendCommand("openHub", { + parentSerialNumber: this.serialNumber, + parentHubAddress: this.moduleAddress, + hubAddress: moduleAddress, + }); + let newHub = new ControlHubConnected( + false, + RevHubType.ExpansionHub, + this.sendCommand, + this.serialNumber, + moduleAddress, + id, + ); + + this.children.push(newHub); + + return newHub; + } +} diff --git a/packages/core/src/ControlHub.ts b/packages/core/src/ControlHub.ts index 01ce2a91..b59bfc0e 100644 --- a/packages/core/src/ControlHub.ts +++ b/packages/core/src/ControlHub.ts @@ -1,4 +1,9 @@ import { ExpansionHub } from "./ExpansionHub.js"; import { ParentRevHub } from "./RevHub.js"; -export interface ControlHub extends ExpansionHub, ParentRevHub {} +export interface ControlHub extends ExpansionHub, ParentRevHub { + addHubBySerialNumberAndAddress( + serialNumber: string, + moduleAddress: number, + ): Promise; +} diff --git a/packages/core/src/RevHub.ts b/packages/core/src/RevHub.ts index dc7095c2..ded4fdff 100644 --- a/packages/core/src/RevHub.ts +++ b/packages/core/src/RevHub.ts @@ -21,6 +21,5 @@ export interface ParentRevHub extends RevHub { readonly children: ReadonlyArray; readonly serialNumber: string; - addChild(hub: RevHub): void; addChildByAddress(moduleAddress: number): Promise; } diff --git a/packages/sample/src/HubStringify.ts b/packages/sample/src/HubStringify.ts index 77d9e5fd..7b25a516 100644 --- a/packages/sample/src/HubStringify.ts +++ b/packages/sample/src/HubStringify.ts @@ -1,12 +1,17 @@ -import { RevHub } from "@rev-robotics/rev-hub-core"; +import { ControlHub, RevHub } from "@rev-robotics/rev-hub-core"; -export function hubHierarchyToString(hub: RevHub): string { +export function controlHubHierarchyToString(hub: ControlHub): string { let result = ""; + result = `Control Hub: ${hub.serialNumber} ${hub.moduleAddress}\n`; + for (const child of hub.children) { + if (child.isParent()) { + result += `\tUSB Hub: ${child.serialNumber} ${child.moduleAddress}\n`; - if (hub.isParent()) { - result = `USB Expansion Hub: ${hub.serialNumber} ${hub.moduleAddress}\n`; - for (const child of hub.children) { - result += `\tUSB Expansion Hub: ${child.moduleAddress}\n`; + for (const grandchild of child.children) { + result += `\t\tRS-485 Hub: ${grandchild.moduleAddress}\n`; + } + } else { + result += `\tRS-485 Hub: ${child.moduleAddress}\n`; } } diff --git a/packages/sample/src/adb-setup.ts b/packages/sample/src/adb-setup.ts index e11583fd..04c678eb 100644 --- a/packages/sample/src/adb-setup.ts +++ b/packages/sample/src/adb-setup.ts @@ -15,7 +15,7 @@ export async function openUsbControlHubs(): Promise { let port = await configureHubTcp(deviceClient); let serialNumber = device.id; - let hub = await openControlHub("(embedded)", 173, port); + let hub = await openControlHub(serialNumber, 173, port); controlHubs.push(hub); } } diff --git a/packages/sample/src/command/list.ts b/packages/sample/src/command/list.ts index 5492e19b..5de9a8a7 100644 --- a/packages/sample/src/command/list.ts +++ b/packages/sample/src/command/list.ts @@ -1,13 +1,16 @@ import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; -import { hubHierarchyToString } from "../HubStringify.js"; -import { openConnectedControlHub } from "@rev-robotics/control-hub"; +import { controlHubHierarchyToString } from "../HubStringify.js"; +import { + openConnectedControlHub, + openUsbControlHubsAndChildren, +} from "@rev-robotics/control-hub"; import { ExpansionHub } from "@rev-robotics/rev-hub-core"; -import { openUsbControlHubs } from "../adb-setup.js"; export async function list() { - let usbControlHubs = await openUsbControlHubs(); + let usbControlHubs = await openUsbControlHubsAndChildren(); for (const hub of usbControlHubs) { - console.log(`USB Control Hub: ${hub.serialNumber} ${hub.moduleAddress}\n\n`); + let hierarchy = controlHubHierarchyToString(hub); + console.log(hierarchy); hub.close(); } @@ -23,7 +26,7 @@ export async function list() { console.log(`Got error:`); console.log(e); }); - console.log(hubHierarchyToString(hub)); + //console.log(controlHubHierarchyToString(hub)); } hubs.forEach((hub) => { hub.close(); diff --git a/packages/sample/src/command/servo.ts b/packages/sample/src/command/servo.ts index bb245e52..eb99a29b 100644 --- a/packages/sample/src/command/servo.ts +++ b/packages/sample/src/command/servo.ts @@ -1,8 +1,7 @@ -import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; -import { openUsbControlHubs } from "../adb-setup.js"; +import { openUsbControlHubsAndChildren } from "@rev-robotics/control-hub"; export async function runServo(channel: number, pulseWidth: number, framePeriod: number) { - const hubs = await openUsbControlHubs(); + const hubs = await openUsbControlHubsAndChildren(); for (let hub of hubs) { await hub.setServoConfiguration(channel, framePeriod); diff --git a/tsconfig.json b/tsconfig.json index 57279bb1..a6aba527 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "strict": true, "lib": ["es2021"], "target": "es2021", + "sourceMap": true, "types": [ "node" ], From a0f433e7b803d0339707cabb8f6a1caf298f1e0b Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 15 Jun 2023 15:56:19 -0500 Subject: [PATCH 035/148] connect to other expansion hubs --- .../control-hub/src/internal/ControlHub.ts | 4 ++-- .../src/internal/ControlHubConnected.ts | 4 ++-- packages/sample/src/command/analog.ts | 10 +++++---- packages/sample/src/command/servo.ts | 21 ++++++++++++------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 43360f61..cb789e8e 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -119,7 +119,7 @@ export class ControlHubInternal implements ControlHub { this.embedded = new ControlHubConnected( true, RevHubType.ControlHub, - this.sendCommand, + this.sendCommand.bind(this), "(embedded)", this.moduleAddress, this.id, @@ -551,7 +551,7 @@ export class ControlHubInternal implements ControlHub { serialNumber: string, moduleAddress: number, ): Promise { - let id: any = this.openHub(serialNumber, moduleAddress, moduleAddress); + let id = await this.openHub(serialNumber, moduleAddress, moduleAddress); let newHub = new ControlHubConnected( true, diff --git a/packages/control-hub/src/internal/ControlHubConnected.ts b/packages/control-hub/src/internal/ControlHubConnected.ts index aa0c5cf7..13895d04 100644 --- a/packages/control-hub/src/internal/ControlHubConnected.ts +++ b/packages/control-hub/src/internal/ControlHubConnected.ts @@ -22,7 +22,7 @@ import { export class ControlHubConnected implements ParentExpansionHub { isParentHub: boolean; type: RevHubType; - id: any; + id: Exclude>; serialNumber: string; moduleAddress: number; sendCommand: (name: string, params: P, timeout?: number) => Promise; @@ -626,7 +626,7 @@ export class ControlHubConnected implements ParentExpansionHub { let newHub = new ControlHubConnected( false, RevHubType.ExpansionHub, - this.sendCommand, + this.sendCommand.bind(this), this.serialNumber, moduleAddress, id, diff --git a/packages/sample/src/command/analog.ts b/packages/sample/src/command/analog.ts index ab664ea1..4cb2762b 100644 --- a/packages/sample/src/command/analog.ts +++ b/packages/sample/src/command/analog.ts @@ -1,16 +1,18 @@ -import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; import { openUsbControlHubs } from "../adb-setup.js"; +import { ExpansionHub, ParentExpansionHub } from "@rev-robotics/rev-hub-core"; +import { openUsbControlHubsAndChildren } from "@rev-robotics/control-hub"; export async function analog(channel: number, continuous: boolean) { - const hubs = await openUsbControlHubs(); + const hubs = await openUsbControlHubsAndChildren(); + let hub: ExpansionHub = hubs[0].children[1] as ExpansionHub; if (continuous) { while (true) { - let value = await hubs[0].getAnalogInput(channel); + let value = await hub.getAnalogInput(channel); console.log(`ADC: ${value} mV`); } } else { - let value = await hubs[0].getAnalogInput(channel); + let value = await hub.getAnalogInput(channel); console.log(`ADC: ${value} mV`); hubs.forEach((hub) => { hub.close(); diff --git a/packages/sample/src/command/servo.ts b/packages/sample/src/command/servo.ts index eb99a29b..9353e8f5 100644 --- a/packages/sample/src/command/servo.ts +++ b/packages/sample/src/command/servo.ts @@ -1,15 +1,20 @@ import { openUsbControlHubsAndChildren } from "@rev-robotics/control-hub"; +import { ExpansionHub } from "@rev-robotics/rev-hub-core"; export async function runServo(channel: number, pulseWidth: number, framePeriod: number) { + console.log("Opening hubs"); const hubs = await openUsbControlHubsAndChildren(); + console.log("Hubs opened"); + let hub: ExpansionHub = hubs[0].children[1] as ExpansionHub; + console.log(`Got hub: ${hub}`); - for (let hub of hubs) { - await hub.setServoConfiguration(channel, framePeriod); - await hub.setServoPulseWidth(channel, pulseWidth); - await hub.setServoEnable(channel, true); + await hub.setServoConfiguration(channel, framePeriod); + await hub.setServoPulseWidth(channel, pulseWidth); + await hub.setServoEnable(channel, true); - setTimeout(() => { - hub.close(); - }, 10000); - } + console.log("Finished sending commands"); + + setTimeout(() => { + hub.close(); + }, 10000); } From a9394d00b98b2fbbb47f17d07152a1f93a3ba428 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 15 Jun 2023 16:38:15 -0500 Subject: [PATCH 036/148] allow user to specify just control hub --- packages/sample/src/main.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 611a7b0c..a6a5112d 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -134,10 +134,14 @@ async function getExpansionHubOrThrow(): Promise { moduleAddress!, ); } else { - return await controlHub.addHubBySerialNumberAndAddress( - "(embedded)", - moduleAddress!, - ); + if (moduleAddress !== undefined) { + return await controlHub.addHubBySerialNumberAndAddress( + "(embedded)", + moduleAddress!, + ); + } else { + return controlHub; + } } } else { if (serialNumber) { From 403a6728e890173d02845936168e894caae62d3a Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 15 Jun 2023 16:53:13 -0500 Subject: [PATCH 037/148] change names of some parameters --- packages/control-hub/src/internal/ControlHubConnected.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHubConnected.ts b/packages/control-hub/src/internal/ControlHubConnected.ts index 13895d04..e349a121 100644 --- a/packages/control-hub/src/internal/ControlHubConnected.ts +++ b/packages/control-hub/src/internal/ControlHubConnected.ts @@ -58,7 +58,7 @@ export class ControlHubConnected implements ParentExpansionHub { async getAnalogInput(channel: number): Promise { return await this.sendCommand("getAnalogInput", { id: this.id, - channel: channel, + analogChannel: channel, }); } @@ -95,6 +95,7 @@ export class ControlHubConnected implements ParentExpansionHub { async getMotorCurrent(motorChannel: number): Promise { return await this.sendCommand("getMotorCurrent", { id: this.id, + motorChannel: motorChannel, }); } @@ -125,7 +126,7 @@ export class ControlHubConnected implements ParentExpansionHub { async getDigitalDirection(dioPin: number): Promise { let isOutput = await this.sendCommand("getDigitalDirection", { id: this.id, - channel: dioPin, + digitalChannel: dioPin, }); return isOutput ? DioDirection.Output : DioDirection.Input; @@ -134,7 +135,7 @@ export class ControlHubConnected implements ParentExpansionHub { async getDigitalSingleInput(dioPin: number): Promise { return await this.sendCommand("getDigitalInput", { id: this.id, - channel: dioPin, + digitalChannel: dioPin, }); } @@ -419,7 +420,7 @@ export class ControlHubConnected implements ParentExpansionHub { async setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { await this.sendCommand("readVersionString", { id: this.id, - pin: dioPin, + digitalChannel: dioPin, value: value ?? false, }); } From 7ac27495b65097dfd4c440e6400aa0d751f7171c Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 16 Jun 2023 08:48:49 -0500 Subject: [PATCH 038/148] handle specified parent --- packages/sample/src/main.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index a6a5112d..21cea1d5 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -129,10 +129,21 @@ async function getExpansionHubOrThrow(): Promise { let controlHub = controlHubs[0]; if (serialNumber) { - return await controlHub.addHubBySerialNumberAndAddress( + if (moduleAddress === undefined) { + moduleAddress = parentAddress; + } + let parent = await controlHub.addHubBySerialNumberAndAddress( serialNumber, - moduleAddress!, + parentAddress!, ); + if (parentAddress === moduleAddress) { + return parent; + } + if (parent.isParent()) { + return (await parent.addChildByAddress(moduleAddress!)) as ExpansionHub; + } else { + throw new Error(); + } } else { if (moduleAddress !== undefined) { return await controlHub.addHubBySerialNumberAndAddress( From fc2ef25cc3dbf9fc0a31b2ebcccecf885e2ed2c2 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 16 May 2023 13:46:47 -0500 Subject: [PATCH 039/148] Update motor power range and document motor power method --- packages/expansion-hub/src/internal/ExpansionHub.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index 9c941db8..c47459fd 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -511,9 +511,17 @@ export class ExpansionHubInternal implements ExpansionHub { }); } + /** + * Set the power for a motor + * @param motorChannel the motor + * @param powerLevel power in range [-100,100] + */ setMotorConstantPower(motorChannel: number, powerLevel: number): Promise { return this.convertErrorPromise(() => { - return this.nativeRevHub.setMotorConstantPower(motorChannel, powerLevel); + return this.nativeRevHub.setMotorConstantPower( + motorChannel, + powerLevel * 327.67, + ); }); } From ad2b3f5d5de05d6c467d114734616ccfc8a63094 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 16 May 2023 13:54:27 -0500 Subject: [PATCH 040/148] Add sample for setting target position --- packages/sample/src/main.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 21cea1d5..8a652032 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -35,6 +35,7 @@ program .action(async () => { await error(); }); +<<<<<<< HEAD program .command("list") From 314019eb3918677dc81df658f1ed660593885934 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 17 May 2023 16:28:45 -0500 Subject: [PATCH 041/148] Convert range of motor input to [-1,1] --- packages/expansion-hub/src/internal/ExpansionHub.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index c47459fd..a33cf3bf 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -514,13 +514,13 @@ export class ExpansionHubInternal implements ExpansionHub { /** * Set the power for a motor * @param motorChannel the motor - * @param powerLevel power in range [-100,100] + * @param powerLevel power in range [-1,1] */ setMotorConstantPower(motorChannel: number, powerLevel: number): Promise { return this.convertErrorPromise(() => { return this.nativeRevHub.setMotorConstantPower( motorChannel, - powerLevel * 327.67, + powerLevel * 32_767, ); }); } From 49d08c163ba6e6c1ea275ed8ed4911f05dbb4aaa Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 17 May 2023 16:36:37 -0500 Subject: [PATCH 042/148] Add documentation --- packages/expansion-hub/src/internal/ExpansionHub.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index a33cf3bf..2248ecd0 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -511,11 +511,6 @@ export class ExpansionHubInternal implements ExpansionHub { }); } - /** - * Set the power for a motor - * @param motorChannel the motor - * @param powerLevel power in range [-1,1] - */ setMotorConstantPower(motorChannel: number, powerLevel: number): Promise { return this.convertErrorPromise(() => { return this.nativeRevHub.setMotorConstantPower( From 397db5431fb1562dc9fa2fd0b97511bde82907c2 Mon Sep 17 00:00:00 2001 From: Landry Norris <37489471+LandryNorris@users.noreply.github.com> Date: Mon, 22 May 2023 11:16:20 -0500 Subject: [PATCH 043/148] Improve wording Co-authored-by: Noah Andrews --- packages/expansion-hub/src/ExpansionHub.ts | 113 +++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 packages/expansion-hub/src/ExpansionHub.ts diff --git a/packages/expansion-hub/src/ExpansionHub.ts b/packages/expansion-hub/src/ExpansionHub.ts new file mode 100644 index 00000000..9e8a7b99 --- /dev/null +++ b/packages/expansion-hub/src/ExpansionHub.ts @@ -0,0 +1,113 @@ +import { + BulkInputData, + DebugGroup, DIODirection, I2CReadStatus, I2CSpeedCode, I2CWriteStatus, + LEDPattern, + ModuleInterface, + ModuleStatus, PIDCoefficients, + RGB, + VerbosityLevel, Version +} from "@rev-robotics/rhsplib"; +import {ParentRevHub, RevHub} from "./RevHub"; + +export type ParentExpansionHub = ParentRevHub & ExpansionHub + +export interface ExpansionHub extends RevHub { + readonly isOpen: boolean + responseTimeoutMs: number; + + /** + * Closes this hub and releases any resources bound to it. + * If this hub is a parent hub, the serial port will be closed + * and all children will be closed as well. Do not use this hub after + * it has been closed. + */ + close(): void; + sendWriteCommand(packetTypeID: number, payload: number[]): Promise; + sendReadCommand(packetTypeID: number, payload: number[]): Promise; + getModuleStatus(clearStatusAfterResponse: boolean): Promise; + sendKeepAlive(): Promise; + sendFailSafe(): Promise; + setNewModuleAddress(newModuleAddress: number): Promise; + queryInterface(interfaceName: string): Promise; + setModuleLEDColor(red: number, green: number, blue: number): Promise; + getModuleLEDColor(): Promise; + setModuleLEDPattern(ledPattern: LEDPattern): Promise; + getModuleLEDPattern(): Promise; + setDebugLogLevel(debugGroup: DebugGroup, verbosityLevel: VerbosityLevel): Promise; + getInterfacePacketID(interfaceName: string, functionNumber: number): Promise; + + // Device Control + getBulkInputData(): Promise; + getADC(): Promise; + setPhoneChargeControl(chargeEnable: boolean): Promise; + getPhoneChargeControl(): Promise; + injectDataLogHint(hintText: string): Promise; + readVersionString(): Promise; + readVersion(): Promise; + setFTDIResetControl(ftdiResetControl: boolean): Promise; + getFTDIResetControl(): Promise; + + // DIO + setDigitalSingleOutput(dioPin: number, value?: boolean): Promise; + setDigitalAllOutputs(bitPackedField: number): Promise; + setDigitalDirection(dioPin: number, direction: DIODirection): Promise; + getDigitalDirection(dioPin: number): Promise; + getDigitalSingleInput(dioPin: number): Promise; + getDigitalAllInputs(): Promise; + + // I2C + setI2CChannelConfiguration(i2cChannel: number, speedCode: I2CSpeedCode): Promise; + getI2CChannelConfiguration(i2cChannel: number): Promise; + writeI2CSingleByte(i2cChannel: number, slaveAddress: number, byte: number): Promise; + writeI2CMultipleBytes(i2cChannel: number, slaveAddress: number, bytes: number[]): Promise; + getI2CWriteStatus(i2cChannel: number): Promise; + readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise; + readI2CMultipleBytes(i2cChannel: number, slaveAddress: number, numBytesToRead: number): Promise; + writeI2CReadMultipleBytes(i2cChannel: number, slaveAddress: number, numBytesToRead: number, startAddress: number): Promise; + getI2CReadStatus(i2cChannel: number): Promise; + + // Motor + /** + * Configure a specific motor + * @param motorChannel + * @param motorMode 0 for constant power, 1 for constant velocity, 2 for position + * @param floatAtZero whether to coast when power is set to 0. If this is set to true, the motor will brake at 0 instead. + */ + setMotorChannelMode(motorChannel: number, motorMode: number, floatAtZero: boolean): Promise; + getMotorChannelMode(motorChannel: number): Promise<{motorMode: number, floatAtZero: boolean}> + + /** + * Enable a motor. The motor must be configured before enabling. + * @param motorChannel + * @param enable + */ + setMotorChannelEnable(motorChannel: number, enable: boolean): Promise; + getMotorChannelEnable(motorChannel: number): Promise; + setMotorChannelCurrentAlertLevel(motorChannel: number, currentLimit_mA: number): Promise; + getMotorChannelCurrentAlertLevel(motorChannel: number): Promise; + resetMotorEncoder(motorChannel: number): Promise; + + /** + * Set the power for a motor + * @param motorChannel the motor + * @param powerLevel power in range [-1,1] + */ + setMotorConstantPower(motorChannel: number, powerLevel: number): Promise; + getMotorConstantPower(motorChannel: number): Promise; + setMotorTargetVelocity(motorChannel: number, velocity_cps: number): Promise; + getMotorTargetVelocity(motorChannel: number): Promise; + setMotorTargetPosition(motorChannel: number, targetPosition_counts: number, targetTolerance_counts: number): Promise; + getMotorTargetPosition(motorChannel: number): Promise<{targetPosition: number, targetTolerance: number}>; + getMotorAtTarget(motorChannel: number): Promise; + getMotorEncoderPosition(motorChannel: number): Promise; + setMotorPIDCoefficients(motorChannel: number, motorMode: number, pid: PIDCoefficients): Promise; + getMotorPIDCoefficients(motorChannel: number, motorMode: number): Promise; + + // Servo + setServoConfiguration(servoChannel: number, framePeriod: number): Promise; + getServoConfiguration(servoChannel: number): Promise; + setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise; + getServoPulseWidth(servoChannel: number): Promise; + setServoEnable(servoChannel: number, enable: boolean): Promise; + getServoEnable(servoChannel: number): Promise; +} From 464a6b60cbe86dd075716a6cc33f9bd4e6f86699 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Mon, 22 May 2023 11:19:23 -0500 Subject: [PATCH 044/148] Reqire motor parameter for running motors --- packages/sample/src/main.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 8a652032..21cea1d5 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -35,7 +35,6 @@ program .action(async () => { await error(); }); -<<<<<<< HEAD program .command("list") From b78b1824fe140c170ec1acc58a1b9f709ed7585e Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Mon, 22 May 2023 11:44:54 -0500 Subject: [PATCH 045/148] Create MotorMode enum --- packages/expansion-hub/src/ExpansionHub.ts | 113 ------------------ packages/expansion-hub/src/MotorMode.ts | 6 + .../src/internal/ExpansionHub.ts | 9 +- 3 files changed, 11 insertions(+), 117 deletions(-) delete mode 100644 packages/expansion-hub/src/ExpansionHub.ts create mode 100644 packages/expansion-hub/src/MotorMode.ts diff --git a/packages/expansion-hub/src/ExpansionHub.ts b/packages/expansion-hub/src/ExpansionHub.ts deleted file mode 100644 index 9e8a7b99..00000000 --- a/packages/expansion-hub/src/ExpansionHub.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { - BulkInputData, - DebugGroup, DIODirection, I2CReadStatus, I2CSpeedCode, I2CWriteStatus, - LEDPattern, - ModuleInterface, - ModuleStatus, PIDCoefficients, - RGB, - VerbosityLevel, Version -} from "@rev-robotics/rhsplib"; -import {ParentRevHub, RevHub} from "./RevHub"; - -export type ParentExpansionHub = ParentRevHub & ExpansionHub - -export interface ExpansionHub extends RevHub { - readonly isOpen: boolean - responseTimeoutMs: number; - - /** - * Closes this hub and releases any resources bound to it. - * If this hub is a parent hub, the serial port will be closed - * and all children will be closed as well. Do not use this hub after - * it has been closed. - */ - close(): void; - sendWriteCommand(packetTypeID: number, payload: number[]): Promise; - sendReadCommand(packetTypeID: number, payload: number[]): Promise; - getModuleStatus(clearStatusAfterResponse: boolean): Promise; - sendKeepAlive(): Promise; - sendFailSafe(): Promise; - setNewModuleAddress(newModuleAddress: number): Promise; - queryInterface(interfaceName: string): Promise; - setModuleLEDColor(red: number, green: number, blue: number): Promise; - getModuleLEDColor(): Promise; - setModuleLEDPattern(ledPattern: LEDPattern): Promise; - getModuleLEDPattern(): Promise; - setDebugLogLevel(debugGroup: DebugGroup, verbosityLevel: VerbosityLevel): Promise; - getInterfacePacketID(interfaceName: string, functionNumber: number): Promise; - - // Device Control - getBulkInputData(): Promise; - getADC(): Promise; - setPhoneChargeControl(chargeEnable: boolean): Promise; - getPhoneChargeControl(): Promise; - injectDataLogHint(hintText: string): Promise; - readVersionString(): Promise; - readVersion(): Promise; - setFTDIResetControl(ftdiResetControl: boolean): Promise; - getFTDIResetControl(): Promise; - - // DIO - setDigitalSingleOutput(dioPin: number, value?: boolean): Promise; - setDigitalAllOutputs(bitPackedField: number): Promise; - setDigitalDirection(dioPin: number, direction: DIODirection): Promise; - getDigitalDirection(dioPin: number): Promise; - getDigitalSingleInput(dioPin: number): Promise; - getDigitalAllInputs(): Promise; - - // I2C - setI2CChannelConfiguration(i2cChannel: number, speedCode: I2CSpeedCode): Promise; - getI2CChannelConfiguration(i2cChannel: number): Promise; - writeI2CSingleByte(i2cChannel: number, slaveAddress: number, byte: number): Promise; - writeI2CMultipleBytes(i2cChannel: number, slaveAddress: number, bytes: number[]): Promise; - getI2CWriteStatus(i2cChannel: number): Promise; - readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise; - readI2CMultipleBytes(i2cChannel: number, slaveAddress: number, numBytesToRead: number): Promise; - writeI2CReadMultipleBytes(i2cChannel: number, slaveAddress: number, numBytesToRead: number, startAddress: number): Promise; - getI2CReadStatus(i2cChannel: number): Promise; - - // Motor - /** - * Configure a specific motor - * @param motorChannel - * @param motorMode 0 for constant power, 1 for constant velocity, 2 for position - * @param floatAtZero whether to coast when power is set to 0. If this is set to true, the motor will brake at 0 instead. - */ - setMotorChannelMode(motorChannel: number, motorMode: number, floatAtZero: boolean): Promise; - getMotorChannelMode(motorChannel: number): Promise<{motorMode: number, floatAtZero: boolean}> - - /** - * Enable a motor. The motor must be configured before enabling. - * @param motorChannel - * @param enable - */ - setMotorChannelEnable(motorChannel: number, enable: boolean): Promise; - getMotorChannelEnable(motorChannel: number): Promise; - setMotorChannelCurrentAlertLevel(motorChannel: number, currentLimit_mA: number): Promise; - getMotorChannelCurrentAlertLevel(motorChannel: number): Promise; - resetMotorEncoder(motorChannel: number): Promise; - - /** - * Set the power for a motor - * @param motorChannel the motor - * @param powerLevel power in range [-1,1] - */ - setMotorConstantPower(motorChannel: number, powerLevel: number): Promise; - getMotorConstantPower(motorChannel: number): Promise; - setMotorTargetVelocity(motorChannel: number, velocity_cps: number): Promise; - getMotorTargetVelocity(motorChannel: number): Promise; - setMotorTargetPosition(motorChannel: number, targetPosition_counts: number, targetTolerance_counts: number): Promise; - getMotorTargetPosition(motorChannel: number): Promise<{targetPosition: number, targetTolerance: number}>; - getMotorAtTarget(motorChannel: number): Promise; - getMotorEncoderPosition(motorChannel: number): Promise; - setMotorPIDCoefficients(motorChannel: number, motorMode: number, pid: PIDCoefficients): Promise; - getMotorPIDCoefficients(motorChannel: number, motorMode: number): Promise; - - // Servo - setServoConfiguration(servoChannel: number, framePeriod: number): Promise; - getServoConfiguration(servoChannel: number): Promise; - setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise; - getServoPulseWidth(servoChannel: number): Promise; - setServoEnable(servoChannel: number, enable: boolean): Promise; - getServoEnable(servoChannel: number): Promise; -} diff --git a/packages/expansion-hub/src/MotorMode.ts b/packages/expansion-hub/src/MotorMode.ts new file mode 100644 index 00000000..d6f0d0cc --- /dev/null +++ b/packages/expansion-hub/src/MotorMode.ts @@ -0,0 +1,6 @@ + +export enum MotorMode { + CONSTANT_POWER, + CONSTANT_VELOCITY, + TARGET_POSITION +} diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index 2248ecd0..fbf1731f 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -32,6 +32,7 @@ import { RevHubType } from "@rev-robotics/rev-hub-core"; import { RhspLibError } from "../errors/RhspLibError.js"; import { startKeepAlive } from "../start-keep-alive.js"; import { performance } from "perf_hooks"; +import { MotorMode } from "../MotorMode.js"; export class ExpansionHubInternal implements ExpansionHub { constructor(isParent: true, serial: SerialPort, serialNumber: string); @@ -264,7 +265,7 @@ export class ExpansionHubInternal implements ExpansionHub { getMotorChannelMode( motorChannel: number, - ): Promise<{ motorMode: number; floatAtZero: boolean }> { + ): Promise<{ motorMode: MotorMode; floatAtZero: boolean }> { return this.convertErrorPromise(() => { return this.nativeRevHub.getMotorChannelMode(motorChannel); }); @@ -284,7 +285,7 @@ export class ExpansionHubInternal implements ExpansionHub { getMotorPIDCoefficients( motorChannel: number, - motorMode: number, + motorMode: MotorMode, ): Promise { return this.convertErrorPromise(() => { return this.nativeRevHub.getMotorPIDCoefficients(motorChannel, motorMode); @@ -499,7 +500,7 @@ export class ExpansionHubInternal implements ExpansionHub { setMotorChannelMode( motorChannel: number, - motorMode: number, + motorMode: MotorMode, floatAtZero: boolean, ): Promise { return this.convertErrorPromise(() => { @@ -522,7 +523,7 @@ export class ExpansionHubInternal implements ExpansionHub { setMotorPIDCoefficients( motorChannel: number, - motorMode: number, + motorMode: MotorMode, pid: PidCoefficients, ): Promise { return this.convertErrorPromise(() => { From 5bafeaef3ebc0f2a651052e4dcb5e6928431d1a8 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Mon, 22 May 2023 11:54:21 -0500 Subject: [PATCH 046/148] Add clarifying comment --- packages/expansion-hub/src/MotorMode.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/expansion-hub/src/MotorMode.ts b/packages/expansion-hub/src/MotorMode.ts index d6f0d0cc..9c9e9241 100644 --- a/packages/expansion-hub/src/MotorMode.ts +++ b/packages/expansion-hub/src/MotorMode.ts @@ -1,4 +1,6 @@ +//The order of these should match the RHSPlib documentation. We rely on the +//numerical value matching. export enum MotorMode { CONSTANT_POWER, CONSTANT_VELOCITY, From a06465996d89b1c0a617a05347cabef31cf70480 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Mon, 22 May 2023 14:47:56 -0500 Subject: [PATCH 047/148] Add motor commands --- packages/core/src/ExpansionHub.ts | 6 ++++++ packages/sample/package.json | 4 +++- packages/sample/src/commands/motor.ts | 20 ++++++++++++++++++++ packages/sample/src/main.ts | 19 +++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 packages/sample/src/commands/motor.ts diff --git a/packages/core/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts index bc2eb821..9534cde2 100644 --- a/packages/core/src/ExpansionHub.ts +++ b/packages/core/src/ExpansionHub.ts @@ -161,6 +161,12 @@ export interface ExpansionHub extends RevHub { resetMotorEncoder(motorChannel: number): Promise; setMotorConstantPower(motorChannel: number, powerLevel: number): Promise; getMotorConstantPower(motorChannel: number): Promise; + + /** + * Set the target velocity for a motor + * @param motorChannel the motor + * @param velocity_cps velocity in encoder counts per second + */ setMotorTargetVelocity(motorChannel: number, velocity_cps: number): Promise; getMotorTargetVelocity(motorChannel: number): Promise; setMotorTargetPosition( diff --git a/packages/sample/package.json b/packages/sample/package.json index 6c6d879c..ed99554d 100644 --- a/packages/sample/package.json +++ b/packages/sample/package.json @@ -27,6 +27,8 @@ "temperature": "node dist/main.js temperature --continuous", "error": "node dist/main.js testErrorHandling", "list": "node dist/main.js list", - "led": "node dist/main.js led" + "led": "node dist/main.js led", + "motor": "node dist/main.js motor power 1 0.60", + "motor-position": "node dist/main.js --count 3000" } } diff --git a/packages/sample/src/commands/motor.ts b/packages/sample/src/commands/motor.ts new file mode 100644 index 00000000..ae2dcc09 --- /dev/null +++ b/packages/sample/src/commands/motor.ts @@ -0,0 +1,20 @@ +import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; +import { MotorMode } from "@rev-robotics/expansion-hub/dist/MotorMode.js"; + +export async function runMotorConstantPower(channel: number, power: number) { + const hubs = await openConnectedExpansionHubs(); + let hub = hubs[0]; + + await hub.setMotorChannelMode(channel, MotorMode.CONSTANT_POWER, true); + await hub.setMotorConstantPower(channel, power); + await hub.setMotorChannelEnable(channel, true); +} + +export async function runMotorConstantVelocity(channel: number, velocity: number) { + const hubs = await openConnectedExpansionHubs(); + let hub = hubs[0]; + + await hub.setMotorChannelMode(channel, MotorMode.CONSTANT_VELOCITY, true); + await hub.setMotorTargetVelocity(channel, velocity); + await hub.setMotorChannelEnable(channel, true); +} diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 21cea1d5..b1e484ac 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -12,6 +12,7 @@ import { openHubWithAddress, openParentExpansionHub, } from "@rev-robotics/expansion-hub"; +import { runMotorConstantPower, runMotorConstantVelocity } from "./commands/motor.js"; const program = new Command(); @@ -36,6 +37,24 @@ program await error(); }); +let motorCommand = program.command("motor"); + +motorCommand.command("power ").action(async (channel, power) => { + console.log(`${channel} ${power}`); + let channelNumber = Number(channel); + let powerNumber = Number(power); + await runMotorConstantPower(channelNumber, powerNumber); +}); + +motorCommand + .command("velocity ") + .action(async (channel, speed) => { + console.log(`${channel} ${speed}`); + let channelNumber = Number(channel); + let speedNumber = Number(speed); + await runMotorConstantVelocity(channelNumber, speedNumber); + }); + program .command("list") .description("List all connected expansion hubs") From 011722bdba9975fefc68b47be057407c5c96611a Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 24 May 2023 15:27:02 -0500 Subject: [PATCH 048/148] Change order of command declaration --- packages/sample/src/main.ts | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index b1e484ac..ebfbee35 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -37,6 +37,21 @@ program await error(); }); +program + .command("list") + .description("List all connected expansion hubs") + .action(async () => { + await list(); + }); + +program + .command("led") + .description("Run LED steps") + .action(async () => { + let hub = await getExpansionHubOrThrow(); + await led(hub); + }); + let motorCommand = program.command("motor"); motorCommand.command("power ").action(async (channel, power) => { @@ -46,14 +61,12 @@ motorCommand.command("power ").action(async (channel, power) => await runMotorConstantPower(channelNumber, powerNumber); }); -motorCommand - .command("velocity ") - .action(async (channel, speed) => { - console.log(`${channel} ${speed}`); - let channelNumber = Number(channel); - let speedNumber = Number(speed); - await runMotorConstantVelocity(channelNumber, speedNumber); - }); +motorCommand.command("velocity ").action(async (channel, speed) => { + console.log(`${channel} ${speed}`); + let channelNumber = Number(channel); + let speedNumber = Number(speed); + await runMotorConstantVelocity(channelNumber, speedNumber); +}); program .command("list") From 3ddfe419e5ed3dfadd010dd5d36e2e47fc66b274 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 11:38:42 -0500 Subject: [PATCH 049/148] Document motor methods --- packages/core/src/ExpansionHub.ts | 54 +++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/packages/core/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts index 9534cde2..d297f2ab 100644 --- a/packages/core/src/ExpansionHub.ts +++ b/packages/core/src/ExpansionHub.ts @@ -148,18 +148,39 @@ export interface ExpansionHub extends RevHub { motorMode: number, floatAtZero: boolean, ): Promise; + + /** + * + * Get the configuration for a specific motor + * @param motorChannel + */ getMotorChannelMode( motorChannel: number, ): Promise<{ motorMode: number; floatAtZero: boolean }>; setMotorChannelEnable(motorChannel: number, enable: boolean): Promise; + + /** + * Check whether a motor channel is currently enabled + * @param motorChannel + */ getMotorChannelEnable(motorChannel: number): Promise; setMotorChannelCurrentAlertLevel( motorChannel: number, currentLimit_mA: number, ): Promise; + + /** + * Get the present current alert (mA) + * @param motorChannel + */ getMotorChannelCurrentAlertLevel(motorChannel: number): Promise; resetMotorEncoder(motorChannel: number): Promise; setMotorConstantPower(motorChannel: number, powerLevel: number): Promise; + + /** + * Get the current constant power setting for a motor + * @param motorChannel + */ getMotorConstantPower(motorChannel: number): Promise; /** @@ -168,22 +189,55 @@ export interface ExpansionHub extends RevHub { * @param velocity_cps velocity in encoder counts per second */ setMotorTargetVelocity(motorChannel: number, velocity_cps: number): Promise; + + /** + * Get the current target velocity for a motor + * @param motorChannel + */ getMotorTargetVelocity(motorChannel: number): Promise; setMotorTargetPosition( motorChannel: number, targetPosition_counts: number, targetTolerance_counts: number, ): Promise; + + /** + * Get the current target position for a motor + * @param motorChannel + */ getMotorTargetPosition( motorChannel: number, ): Promise<{ targetPosition: number; targetTolerance: number }>; + + /** + * Check if a motor has reached its target + * @param motorChannel + */ getMotorAtTarget(motorChannel: number): Promise; + + /** + * Get the current encoder counts for a motor + * @param motorChannel + */ getMotorEncoderPosition(motorChannel: number): Promise; + + /** + * Set the current PID coefficients for a motor + * @param motorChannel + * @param motorMode + * @param pid + */ setMotorPIDCoefficients( motorChannel: number, motorMode: number, pid: PidCoefficients, ): Promise; + + /** + * Get the current PID coefficients for a motor + * @param motorChannel + * @param motorMode + */ getMotorPIDCoefficients( motorChannel: number, motorMode: number, From 223a2011f256fcb51f7372475dbcf3d2c20ced51 Mon Sep 17 00:00:00 2001 From: Landry Norris <37489471+LandryNorris@users.noreply.github.com> Date: Tue, 30 May 2023 12:49:18 -0500 Subject: [PATCH 050/148] Improve wording Co-authored-by: Noah Andrews --- packages/core/src/ExpansionHub.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts index d297f2ab..574bd275 100644 --- a/packages/core/src/ExpansionHub.ts +++ b/packages/core/src/ExpansionHub.ts @@ -170,7 +170,7 @@ export interface ExpansionHub extends RevHub { ): Promise; /** - * Get the present current alert (mA) + * Get the current level in mA that will trigger the current alert for a given motor channel * @param motorChannel */ getMotorChannelCurrentAlertLevel(motorChannel: number): Promise; From 1960f1db3f24d5f5df7c32ae32ba7183bc1381d7 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 30 May 2023 12:59:17 -0500 Subject: [PATCH 051/148] Add documentation --- packages/core/src/ExpansionHub.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/core/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts index 574bd275..a1e646dd 100644 --- a/packages/core/src/ExpansionHub.ts +++ b/packages/core/src/ExpansionHub.ts @@ -164,6 +164,12 @@ export interface ExpansionHub extends RevHub { * @param motorChannel */ getMotorChannelEnable(motorChannel: number): Promise; + + /** + * Set the current level in mA that will trigger the current alert for a given motor channel + * @param motorChannel + * @param currentLimit_mA Current level in mA that will trigger the current alert + */ setMotorChannelCurrentAlertLevel( motorChannel: number, currentLimit_mA: number, @@ -174,6 +180,11 @@ export interface ExpansionHub extends RevHub { * @param motorChannel */ getMotorChannelCurrentAlertLevel(motorChannel: number): Promise; + + /** + * Reset motor position to 0 counts + * @param motorChannel + */ resetMotorEncoder(motorChannel: number): Promise; setMotorConstantPower(motorChannel: number, powerLevel: number): Promise; @@ -195,10 +206,17 @@ export interface ExpansionHub extends RevHub { * @param motorChannel */ getMotorTargetVelocity(motorChannel: number): Promise; + + /** + * Set the target position for a motor + * @param motorChannel + * @param targetPositionCounts + * @param targetToleranceCounts how far the position can be from the target and still considered 'at target' + */ setMotorTargetPosition( motorChannel: number, - targetPosition_counts: number, - targetTolerance_counts: number, + targetPositionCounts: number, + targetToleranceCounts: number, ): Promise; /** From 8d89d03f1f0090bfcc8f32220273743290c2a50c Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 31 May 2023 12:16:09 -0500 Subject: [PATCH 052/148] Add motor command to get the current encoder position --- packages/sample/src/commands/motor.ts | 9 +++++++++ packages/sample/src/main.ts | 14 +++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/sample/src/commands/motor.ts b/packages/sample/src/commands/motor.ts index ae2dcc09..8085a39f 100644 --- a/packages/sample/src/commands/motor.ts +++ b/packages/sample/src/commands/motor.ts @@ -18,3 +18,12 @@ export async function runMotorConstantVelocity(channel: number, velocity: number await hub.setMotorTargetVelocity(channel, velocity); await hub.setMotorChannelEnable(channel, true); } + +export async function runEncoder(channel: number) { + const hubs = await openConnectedExpansionHubs(); + let hub = hubs[0]; + + let encoder = await hub.getMotorEncoderPosition(channel); + console.log(`Encoder count is ${encoder}`); + hub.close(); +} diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index ebfbee35..c069f063 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -1,6 +1,11 @@ import { Command } from "commander"; import { analog, battery, temperature, voltageRail } from "./command/analog.js"; import { error } from "./command/error.js"; +import { + runEncoder, + runMotorConstantPower, + runMotorConstantVelocity, +} from "./commands/motor.js"; import { list } from "./command/list.js"; import { led } from "./command/led.js"; import { runServo } from "./command/servo.js"; @@ -12,7 +17,6 @@ import { openHubWithAddress, openParentExpansionHub, } from "@rev-robotics/expansion-hub"; -import { runMotorConstantPower, runMotorConstantVelocity } from "./commands/motor.js"; const program = new Command(); @@ -54,6 +58,14 @@ program let motorCommand = program.command("motor"); +motorCommand + .command("encoder ") + .description("Get the current encoder position of a motor") + .action(async (channel) => { + let channelNumber = Number(channel); + await runEncoder(channelNumber); + }); + motorCommand.command("power ").action(async (channel, power) => { console.log(`${channel} ${power}`); let channelNumber = Number(channel); From 5c1c347032a2b2db1f6de3c08faff34302871689 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 31 May 2023 12:30:50 -0500 Subject: [PATCH 053/148] Improve documentation --- packages/core/src/ExpansionHub.ts | 46 +++++++++++++++---- .../{expansion-hub => core}/src/MotorMode.ts | 0 packages/core/src/index.ts | 1 + .../src/internal/ExpansionHub.ts | 3 +- packages/sample/src/commands/motor.ts | 2 +- 5 files changed, 39 insertions(+), 13 deletions(-) rename packages/{expansion-hub => core}/src/MotorMode.ts (100%) diff --git a/packages/core/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts index a1e646dd..61e7cd80 100644 --- a/packages/core/src/ExpansionHub.ts +++ b/packages/core/src/ExpansionHub.ts @@ -12,6 +12,7 @@ import { I2CSpeedCode } from "./I2CSpeedCode.js"; import { I2CWriteStatus } from "./I2CWriteStatus.js"; import { I2CReadStatus } from "./I2CReadStatus.js"; import { PidCoefficients } from "./PidCoefficients.js"; +import { MotorMode } from "./MotorMode.js"; export type ParentExpansionHub = ParentRevHub & ExpansionHub; @@ -143,6 +144,13 @@ export interface ExpansionHub extends RevHub { getI2CReadStatus(i2cChannel: number): Promise; // Motor + /** + * Configure a specific motor + * @param motorChannel + * @param motorMode + * @param floatAtZero whether to coast when power is set to 0. If this is + * set to true, the motor will brake at 0 instead. + */ setMotorChannelMode( motorChannel: number, motorMode: number, @@ -150,13 +158,18 @@ export interface ExpansionHub extends RevHub { ): Promise; /** - * * Get the configuration for a specific motor * @param motorChannel */ getMotorChannelMode( motorChannel: number, - ): Promise<{ motorMode: number; floatAtZero: boolean }>; + ): Promise<{ motorMode: MotorMode; floatAtZero: boolean }>; + + /** + * Enable a motor. The motor must be configured before enabling. + * @param motorChannel + * @param enable + */ setMotorChannelEnable(motorChannel: number, enable: boolean): Promise; /** @@ -182,36 +195,48 @@ export interface ExpansionHub extends RevHub { getMotorChannelCurrentAlertLevel(motorChannel: number): Promise; /** - * Reset motor position to 0 counts + * Reset motor position to 0 counts. * @param motorChannel */ resetMotorEncoder(motorChannel: number): Promise; + + /** + * Set the power for a motor. Assumes the current motor mode is + * 'constant power' + * @param motorChannel the motor + * @param powerLevel power in range [-1,1] + */ setMotorConstantPower(motorChannel: number, powerLevel: number): Promise; /** - * Get the current constant power setting for a motor + * Get the current constant power setting for a motor. Assumes the current + * motor mode is 'constant power' * @param motorChannel */ getMotorConstantPower(motorChannel: number): Promise; /** - * Set the target velocity for a motor + * Set the target velocity for a motor. Assumes the current motor + * mode is 'target velocity' * @param motorChannel the motor * @param velocity_cps velocity in encoder counts per second */ setMotorTargetVelocity(motorChannel: number, velocity_cps: number): Promise; /** - * Get the current target velocity for a motor + * Get the current target velocity for a motor. Assumes the current motor + * mode is 'target velocity' * @param motorChannel */ getMotorTargetVelocity(motorChannel: number): Promise; /** - * Set the target position for a motor + * Set the target position for a motor. Assumes the motor mode is + * 'position target' * @param motorChannel - * @param targetPositionCounts - * @param targetToleranceCounts how far the position can be from the target and still considered 'at target' + * @param targetPositionCounts target position in encoder counts + * @param targetToleranceCounts how far the position can be from the target + * and still considered 'at target' */ setMotorTargetPosition( motorChannel: number, @@ -220,7 +245,8 @@ export interface ExpansionHub extends RevHub { ): Promise; /** - * Get the current target position for a motor + * Get the current target position for a motor. Assumes the current motor + * mode is 'position target' * @param motorChannel */ getMotorTargetPosition( diff --git a/packages/expansion-hub/src/MotorMode.ts b/packages/core/src/MotorMode.ts similarity index 100% rename from packages/expansion-hub/src/MotorMode.ts rename to packages/core/src/MotorMode.ts diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 22690a55..5e8719ee 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -14,6 +14,7 @@ export * from "./ModuleInterface.js"; export * from "./ModuleStatus.js"; export * from "./PidCoefficients.js"; export * from "./Rgb.js"; +export * from "./MotorMode.js"; export * from "./SerialFlowControl.js"; export * from "./SerialParity.js"; export * from "./VerbosityLevel.js"; diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index fbf1731f..26950b59 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -28,11 +28,10 @@ import { } from "@rev-robotics/rev-hub-core"; import { closeSerialPort } from "../open-rev-hub.js"; import { EventEmitter } from "events"; -import { RevHubType } from "@rev-robotics/rev-hub-core"; +import { RevHubType, MotorMode } from "@rev-robotics/rev-hub-core"; import { RhspLibError } from "../errors/RhspLibError.js"; import { startKeepAlive } from "../start-keep-alive.js"; import { performance } from "perf_hooks"; -import { MotorMode } from "../MotorMode.js"; export class ExpansionHubInternal implements ExpansionHub { constructor(isParent: true, serial: SerialPort, serialNumber: string); diff --git a/packages/sample/src/commands/motor.ts b/packages/sample/src/commands/motor.ts index 8085a39f..a2804e77 100644 --- a/packages/sample/src/commands/motor.ts +++ b/packages/sample/src/commands/motor.ts @@ -1,5 +1,5 @@ import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; -import { MotorMode } from "@rev-robotics/expansion-hub/dist/MotorMode.js"; +import { MotorMode } from "@rev-robotics/rev-hub-core"; export async function runMotorConstantPower(channel: number, power: number) { const hubs = await openConnectedExpansionHubs(); From 4c099610da9bf7f8774f0dd9b9c2c9a8246685bb Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 31 May 2023 12:42:43 -0500 Subject: [PATCH 054/148] Create motor encoder reset command --- packages/sample/src/commands/motor.ts | 8 ++++++++ packages/sample/src/main.ts | 10 ++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/sample/src/commands/motor.ts b/packages/sample/src/commands/motor.ts index a2804e77..0074455f 100644 --- a/packages/sample/src/commands/motor.ts +++ b/packages/sample/src/commands/motor.ts @@ -27,3 +27,11 @@ export async function runEncoder(channel: number) { console.log(`Encoder count is ${encoder}`); hub.close(); } + +export async function resetEncoder(channel: number) { + const hubs = await openConnectedExpansionHubs(); + let hub = hubs[0]; + + await hub.resetMotorEncoder(channel); + hub.close(); +} diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index c069f063..ae662f9c 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -2,6 +2,7 @@ import { Command } from "commander"; import { analog, battery, temperature, voltageRail } from "./command/analog.js"; import { error } from "./command/error.js"; import { + resetEncoder, runEncoder, runMotorConstantPower, runMotorConstantVelocity, @@ -60,10 +61,15 @@ let motorCommand = program.command("motor"); motorCommand .command("encoder ") + .option("-r --reset", "reset the encoder count") .description("Get the current encoder position of a motor") - .action(async (channel) => { + .action(async (channel, options) => { let channelNumber = Number(channel); - await runEncoder(channelNumber); + if (options.reset) { + await resetEncoder(channelNumber); + } else { + await runEncoder(channelNumber); + } }); motorCommand.command("power ").action(async (channel, power) => { From 8d4e29e7641471af9ebc84e8245aab06f22e97cb Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 31 May 2023 12:54:30 -0500 Subject: [PATCH 055/148] move motor commands to 'command' folder for consistency --- packages/sample/src/{commands => command}/motor.ts | 0 packages/sample/src/main.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/sample/src/{commands => command}/motor.ts (100%) diff --git a/packages/sample/src/commands/motor.ts b/packages/sample/src/command/motor.ts similarity index 100% rename from packages/sample/src/commands/motor.ts rename to packages/sample/src/command/motor.ts diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index ae662f9c..c831f1f0 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -6,7 +6,7 @@ import { runEncoder, runMotorConstantPower, runMotorConstantVelocity, -} from "./commands/motor.js"; +} from "./command/motor.js"; import { list } from "./command/list.js"; import { led } from "./command/led.js"; import { runServo } from "./command/servo.js"; From a76907e4906c000dd4d79dd9dd7b5895e651b8a2 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 31 May 2023 12:57:12 -0500 Subject: [PATCH 056/148] Add continuous flag to motor encoder --- packages/sample/src/command/motor.ts | 9 ++++++--- packages/sample/src/main.ts | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/sample/src/command/motor.ts b/packages/sample/src/command/motor.ts index 0074455f..5b830fd8 100644 --- a/packages/sample/src/command/motor.ts +++ b/packages/sample/src/command/motor.ts @@ -19,12 +19,15 @@ export async function runMotorConstantVelocity(channel: number, velocity: number await hub.setMotorChannelEnable(channel, true); } -export async function runEncoder(channel: number) { +export async function runEncoder(channel: number, continuous: boolean) { const hubs = await openConnectedExpansionHubs(); let hub = hubs[0]; - let encoder = await hub.getMotorEncoderPosition(channel); - console.log(`Encoder count is ${encoder}`); + while (true) { + let encoder = await hub.getMotorEncoderPosition(channel); + console.log(`Encoder count is ${encoder}`); + if (!continuous) break; + } hub.close(); } diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index c831f1f0..f994dec2 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -62,13 +62,15 @@ let motorCommand = program.command("motor"); motorCommand .command("encoder ") .option("-r --reset", "reset the encoder count") + .option("--continuous", "run continuously") .description("Get the current encoder position of a motor") .action(async (channel, options) => { let channelNumber = Number(channel); if (options.reset) { await resetEncoder(channelNumber); } else { - await runEncoder(channelNumber); + let isContinuous = options.continuous !== undefined; + await runEncoder(channelNumber, isContinuous); } }); From 11ac986f22045cd25bb1c465a3aa268b189f9211 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 31 May 2023 13:17:17 -0500 Subject: [PATCH 057/148] Publish - @rev-robotics/expansion-hub@0.1.0 - @rev-robotics/rhsplib@1.0.6 --- package-lock.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d5ace4fa..b383a5bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7828,9 +7828,6 @@ "typescript": "^5.0.2" } }, - "packages/distance-sensor": { - "extraneous": true - }, "packages/expansion-hub": { "name": "@rev-robotics/expansion-hub", "version": "1.0.0", From 961dad4678abfce9c097bd9e7ef120ccfe701d47 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 7 Jun 2023 09:33:22 -0500 Subject: [PATCH 058/148] Stop motors when sigint signal received --- packages/sample/src/command/motor.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/sample/src/command/motor.ts b/packages/sample/src/command/motor.ts index 5b830fd8..62688459 100644 --- a/packages/sample/src/command/motor.ts +++ b/packages/sample/src/command/motor.ts @@ -8,6 +8,10 @@ export async function runMotorConstantPower(channel: number, power: number) { await hub.setMotorChannelMode(channel, MotorMode.CONSTANT_POWER, true); await hub.setMotorConstantPower(channel, power); await hub.setMotorChannelEnable(channel, true); + process.on("SIGINT", () => { + hub.setMotorChannelEnable(channel, false); + process.exit(); + }); } export async function runMotorConstantVelocity(channel: number, velocity: number) { @@ -17,6 +21,10 @@ export async function runMotorConstantVelocity(channel: number, velocity: number await hub.setMotorChannelMode(channel, MotorMode.CONSTANT_VELOCITY, true); await hub.setMotorTargetVelocity(channel, velocity); await hub.setMotorChannelEnable(channel, true); + process.on("SIGINT", () => { + hub.setMotorChannelEnable(channel, false); + process.exit(); + }); } export async function runEncoder(channel: number, continuous: boolean) { From 9808e64ba6ddf41449ac691375f45f10cdf15008 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 7 Jun 2023 09:49:43 -0500 Subject: [PATCH 059/148] Rename motor modes to be more clear --- packages/core/src/MotorMode.ts | 19 +++++++++++++++---- packages/sample/src/command/motor.ts | 4 ++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/core/src/MotorMode.ts b/packages/core/src/MotorMode.ts index 9c9e9241..eca00a6e 100644 --- a/packages/core/src/MotorMode.ts +++ b/packages/core/src/MotorMode.ts @@ -1,8 +1,19 @@ - //The order of these should match the RHSPlib documentation. We rely on the //numerical value matching. export enum MotorMode { - CONSTANT_POWER, - CONSTANT_VELOCITY, - TARGET_POSITION + /** + * This mode controls the motor's speed by setting the pwm duty cycle. + * It does not require an encoder. + */ + OPEN_LOOP, + /** + * This mode uses the encoder to regulate the velocity of the motor. + * This mode requires an encoder to be connected. + */ + REGULATED_VELOCITY, + /** + * This mode uses an encoder to regulate the position of the motor. + * This mode requires an encoder to be connected. + */ + REGULATED_POSITION, } diff --git a/packages/sample/src/command/motor.ts b/packages/sample/src/command/motor.ts index 62688459..ad3a55ee 100644 --- a/packages/sample/src/command/motor.ts +++ b/packages/sample/src/command/motor.ts @@ -5,7 +5,7 @@ export async function runMotorConstantPower(channel: number, power: number) { const hubs = await openConnectedExpansionHubs(); let hub = hubs[0]; - await hub.setMotorChannelMode(channel, MotorMode.CONSTANT_POWER, true); + await hub.setMotorChannelMode(channel, MotorMode.OPEN_LOOP, true); await hub.setMotorConstantPower(channel, power); await hub.setMotorChannelEnable(channel, true); process.on("SIGINT", () => { @@ -18,7 +18,7 @@ export async function runMotorConstantVelocity(channel: number, velocity: number const hubs = await openConnectedExpansionHubs(); let hub = hubs[0]; - await hub.setMotorChannelMode(channel, MotorMode.CONSTANT_VELOCITY, true); + await hub.setMotorChannelMode(channel, MotorMode.REGULATED_VELOCITY, true); await hub.setMotorTargetVelocity(channel, velocity); await hub.setMotorChannelEnable(channel, true); process.on("SIGINT", () => { From 538e81e4de9792d1e04a79eb141b68d0de57f411 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 7 Jun 2023 10:11:26 -0500 Subject: [PATCH 060/148] Add motor position command --- packages/sample/src/command/motor.ts | 17 +++++++++++++++++ packages/sample/src/main.ts | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/packages/sample/src/command/motor.ts b/packages/sample/src/command/motor.ts index ad3a55ee..4161d3b4 100644 --- a/packages/sample/src/command/motor.ts +++ b/packages/sample/src/command/motor.ts @@ -27,6 +27,23 @@ export async function runMotorConstantVelocity(channel: number, velocity: number }); } +export async function runMotorToPosition( + channel: number, + position: number, + tolerance: number, +) { + const hubs = await openConnectedExpansionHubs(); + let hub = hubs[0]; + + await hub.setMotorChannelMode(channel, MotorMode.REGULATED_POSITION, true); + await hub.setMotorTargetPosition(channel, position, tolerance); + await hub.setMotorChannelEnable(channel, true); + process.on("SIGINT", () => { + hub.setMotorChannelEnable(channel, false); + process.exit(); + }); +} + export async function runEncoder(channel: number, continuous: boolean) { const hubs = await openConnectedExpansionHubs(); let hub = hubs[0]; diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index f994dec2..5267dc7e 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -6,6 +6,7 @@ import { runEncoder, runMotorConstantPower, runMotorConstantVelocity, + runMotorToPosition, } from "./command/motor.js"; import { list } from "./command/list.js"; import { led } from "./command/led.js"; @@ -88,6 +89,16 @@ motorCommand.command("velocity ").action(async (channel, speed) await runMotorConstantVelocity(channelNumber, speedNumber); }); +motorCommand + .command("position ") + .action(async (channel, position, tolerance) => { + console.log(`${channel} ${position} ${tolerance}`); + let channelNumber = Number(channel); + let positionNumber = Number(position); + let toleranceNumber = Number(tolerance); + await runMotorToPosition(channelNumber, positionNumber, toleranceNumber); + }); + program .command("list") .description("List all connected expansion hubs") From e5c59e340944d35d31cd78759c284fb5025fed3e Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 7 Jun 2023 10:15:36 -0500 Subject: [PATCH 061/148] Fix uninitialized motor error for position command --- packages/core/src/ExpansionHub.ts | 4 ++-- packages/sample/src/command/motor.ts | 2 ++ packages/sample/src/main.ts | 12 +++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/core/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts index 61e7cd80..a1ba08ea 100644 --- a/packages/core/src/ExpansionHub.ts +++ b/packages/core/src/ExpansionHub.ts @@ -217,7 +217,7 @@ export interface ExpansionHub extends RevHub { /** * Set the target velocity for a motor. Assumes the current motor - * mode is 'target velocity' + * mode is 'target velocity' or 'position target' * @param motorChannel the motor * @param velocity_cps velocity in encoder counts per second */ @@ -232,7 +232,7 @@ export interface ExpansionHub extends RevHub { /** * Set the target position for a motor. Assumes the motor mode is - * 'position target' + * 'position target' and a velocity has been set using setMotorTargetVelocity. * @param motorChannel * @param targetPositionCounts target position in encoder counts * @param targetToleranceCounts how far the position can be from the target diff --git a/packages/sample/src/command/motor.ts b/packages/sample/src/command/motor.ts index 4161d3b4..844c27dd 100644 --- a/packages/sample/src/command/motor.ts +++ b/packages/sample/src/command/motor.ts @@ -29,6 +29,7 @@ export async function runMotorConstantVelocity(channel: number, velocity: number export async function runMotorToPosition( channel: number, + velocity: number, position: number, tolerance: number, ) { @@ -36,6 +37,7 @@ export async function runMotorToPosition( let hub = hubs[0]; await hub.setMotorChannelMode(channel, MotorMode.REGULATED_POSITION, true); + await hub.setMotorTargetVelocity(channel, velocity); await hub.setMotorTargetPosition(channel, position, tolerance); await hub.setMotorChannelEnable(channel, true); process.on("SIGINT", () => { diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 5267dc7e..d4a736ca 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -90,13 +90,19 @@ motorCommand.command("velocity ").action(async (channel, speed) }); motorCommand - .command("position ") - .action(async (channel, position, tolerance) => { + .command("position ") + .action(async (channel, velocity, position, tolerance) => { console.log(`${channel} ${position} ${tolerance}`); let channelNumber = Number(channel); let positionNumber = Number(position); let toleranceNumber = Number(tolerance); - await runMotorToPosition(channelNumber, positionNumber, toleranceNumber); + let velocityNumber = Number(velocity); + await runMotorToPosition( + channelNumber, + velocityNumber, + positionNumber, + toleranceNumber, + ); }); program From e85ae0b5de0ee0f17c523ad21f96d0106eb96c87 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 7 Jun 2023 10:17:38 -0500 Subject: [PATCH 062/148] Add documentation --- packages/sample/src/main.ts | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index d4a736ca..bf81c5d6 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -75,22 +75,31 @@ motorCommand } }); -motorCommand.command("power ").action(async (channel, power) => { - console.log(`${channel} ${power}`); - let channelNumber = Number(channel); - let powerNumber = Number(power); - await runMotorConstantPower(channelNumber, powerNumber); -}); +motorCommand + .command("power ") + .description( + "Tell a motor to run at a given pwm duty cycle. Power is in the range [-1.0, 1.0]", + ) + .action(async (channel, power) => { + console.log(`${channel} ${power}`); + let channelNumber = Number(channel); + let powerNumber = Number(power); + await runMotorConstantPower(channelNumber, powerNumber); + }); -motorCommand.command("velocity ").action(async (channel, speed) => { - console.log(`${channel} ${speed}`); - let channelNumber = Number(channel); - let speedNumber = Number(speed); - await runMotorConstantVelocity(channelNumber, speedNumber); -}); +motorCommand + .command("velocity ") + .description("Tell a motor to run at a given speed") + .action(async (channel, speed) => { + console.log(`${channel} ${speed}`); + let channelNumber = Number(channel); + let speedNumber = Number(speed); + await runMotorConstantVelocity(channelNumber, speedNumber); + }); motorCommand .command("position ") + .description("Tell a motor to run to a given position") .action(async (channel, velocity, position, tolerance) => { console.log(`${channel} ${position} ${tolerance}`); let channelNumber = Number(channel); From 1f65dcf993ab7068457e60385d0e8f30e17d6602 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 9 Jun 2023 16:51:56 -0500 Subject: [PATCH 063/148] apply latest changes to control hub --- packages/control-hub/src/internal/ControlHub.ts | 6 +----- packages/sample/src/command/motor.ts | 3 ++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index bac4a61d..bcf5d538 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -540,10 +540,6 @@ export class ControlHubInternal implements ControlHub { return this.embedded.writeI2CSingleByte(i2cChannel, slaveAddress, byte); } - async addChild(hub: RevHub): Promise { - throw new Error("not implemented"); - } - async addChildByAddress(moduleAddress: number): Promise { return this.addHubBySerialNumberAndAddress(this.serialNumber, moduleAddress); } @@ -602,7 +598,7 @@ export class ControlHubInternal implements ControlHub { let timer!: NodeJS.Timer; let timeoutPromise: Promise = new Promise((_, reject) => { timer = setTimeout(() => { - console.log(`Got timeout for ${type}`); + console.error(`Got timeout for ${type}`); reject(new TimeoutError()); }, timeout); }); diff --git a/packages/sample/src/command/motor.ts b/packages/sample/src/command/motor.ts index 844c27dd..81ff1491 100644 --- a/packages/sample/src/command/motor.ts +++ b/packages/sample/src/command/motor.ts @@ -8,8 +8,9 @@ export async function runMotorConstantPower(channel: number, power: number) { await hub.setMotorChannelMode(channel, MotorMode.OPEN_LOOP, true); await hub.setMotorConstantPower(channel, power); await hub.setMotorChannelEnable(channel, true); + process.on("SIGINT", () => { - hub.setMotorChannelEnable(channel, false); + hub.close(); process.exit(); }); } From aa5b93fd816dc3bd567ed8c852b9449d84999fa4 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Mon, 22 May 2023 16:23:17 -0500 Subject: [PATCH 064/148] Convert to commands for sample --- packages/expansion-hub/src/ExpansionHub.ts | 146 +++++++++++++++++++++ packages/sample/src/commands/digital.ts | 26 ++++ packages/sample/src/main.ts | 21 +++ 3 files changed, 193 insertions(+) create mode 100644 packages/expansion-hub/src/ExpansionHub.ts create mode 100644 packages/sample/src/commands/digital.ts diff --git a/packages/expansion-hub/src/ExpansionHub.ts b/packages/expansion-hub/src/ExpansionHub.ts new file mode 100644 index 00000000..a8578b42 --- /dev/null +++ b/packages/expansion-hub/src/ExpansionHub.ts @@ -0,0 +1,146 @@ +import { + BulkInputData, + DebugGroup, + DIODirection, + I2CReadStatus, + I2CSpeedCode, + I2CWriteStatus, + LEDPattern, + ModuleInterface, + ModuleStatus, + PIDCoefficients, + RGB, + VerbosityLevel, + Version, +} from "@rev-robotics/rhsplib"; +import { ParentRevHub, RevHub } from "./RevHub"; + +export type ParentExpansionHub = ParentRevHub & ExpansionHub; + +export interface ExpansionHub extends RevHub { + readonly isOpen: boolean; + responseTimeoutMs: number; + + /** + * Closes this hub and releases any resources bound to it. + * If this hub is a parent hub, the serial port will be closed + * and all children will be closed as well. Do not use this hub after + * it has been closed. + */ + close(): void; + sendWriteCommand(packetTypeID: number, payload: number[]): Promise; + sendReadCommand(packetTypeID: number, payload: number[]): Promise; + getModuleStatus(clearStatusAfterResponse: boolean): Promise; + sendKeepAlive(): Promise; + sendFailSafe(): Promise; + setNewModuleAddress(newModuleAddress: number): Promise; + queryInterface(interfaceName: string): Promise; + setModuleLedColor(red: number, green: number, blue: number): Promise; + getModuleLedColor(): Promise; + setModuleLedPattern(ledPattern: LEDPattern): Promise; + getModuleLedPattern(): Promise; + setDebugLogLevel( + debugGroup: DebugGroup, + verbosityLevel: VerbosityLevel, + ): Promise; + getInterfacePacketID(interfaceName: string, functionNumber: number): Promise; + + // Device Control + getBulkInputData(): Promise; + getADC(): Promise; + setPhoneChargeControl(chargeEnable: boolean): Promise; + getPhoneChargeControl(): Promise; + injectDataLogHint(hintText: string): Promise; + readVersionString(): Promise; + readVersion(): Promise; + setFTDIResetControl(ftdiResetControl: boolean): Promise; + getFTDIResetControl(): Promise; + + // DIO + setDigitalSingleOutput(digitalChannel: number, value?: boolean): Promise; + setDigitalAllOutputs(bitPackedField: number): Promise; + setDigitalDirection(digitalChannel: number, direction: DIODirection): Promise; + getDigitalDirection(digitalChannel: number): Promise; + getDigitalSingleInput(digitalChannel: number): Promise; + getDigitalAllInputs(): Promise; + + // I2C + setI2CChannelConfiguration( + i2cChannel: number, + speedCode: I2CSpeedCode, + ): Promise; + getI2CChannelConfiguration(i2cChannel: number): Promise; + writeI2CSingleByte( + i2cChannel: number, + slaveAddress: number, + byte: number, + ): Promise; + writeI2CMultipleBytes( + i2cChannel: number, + slaveAddress: number, + bytes: number[], + ): Promise; + getI2CWriteStatus(i2cChannel: number): Promise; + readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise; + readI2CMultipleBytes( + i2cChannel: number, + slaveAddress: number, + numBytesToRead: number, + ): Promise; + writeI2CReadMultipleBytes( + i2cChannel: number, + slaveAddress: number, + numBytesToRead: number, + startAddress: number, + ): Promise; + getI2CReadStatus(i2cChannel: number): Promise; + + // Motor + setMotorChannelMode( + motorChannel: number, + motorMode: number, + floatAtZero: boolean, + ): Promise; + getMotorChannelMode( + motorChannel: number, + ): Promise<{ motorMode: number; floatAtZero: boolean }>; + setMotorChannelEnable(motorChannel: number, enable: boolean): Promise; + getMotorChannelEnable(motorChannel: number): Promise; + setMotorChannelCurrentAlertLevel( + motorChannel: number, + currentLimit_mA: number, + ): Promise; + getMotorChannelCurrentAlertLevel(motorChannel: number): Promise; + resetMotorEncoder(motorChannel: number): Promise; + setMotorConstantPower(motorChannel: number, powerLevel: number): Promise; + getMotorConstantPower(motorChannel: number): Promise; + setMotorTargetVelocity(motorChannel: number, velocity_cps: number): Promise; + getMotorTargetVelocity(motorChannel: number): Promise; + setMotorTargetPosition( + motorChannel: number, + targetPosition_counts: number, + targetTolerance_counts: number, + ): Promise; + getMotorTargetPosition( + motorChannel: number, + ): Promise<{ targetPosition: number; targetTolerance: number }>; + getMotorAtTarget(motorChannel: number): Promise; + getMotorEncoderPosition(motorChannel: number): Promise; + setMotorPIDCoefficients( + motorChannel: number, + motorMode: number, + pid: PIDCoefficients, + ): Promise; + getMotorPIDCoefficients( + motorChannel: number, + motorMode: number, + ): Promise; + + // Servo + setServoConfiguration(servoChannel: number, framePeriod: number): Promise; + getServoConfiguration(servoChannel: number): Promise; + setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise; + getServoPulseWidth(servoChannel: number): Promise; + setServoEnable(servoChannel: number, enable: boolean): Promise; + getServoEnable(servoChannel: number): Promise; +} diff --git a/packages/sample/src/commands/digital.ts b/packages/sample/src/commands/digital.ts new file mode 100644 index 00000000..5cd4a446 --- /dev/null +++ b/packages/sample/src/commands/digital.ts @@ -0,0 +1,26 @@ +import { DIODirection } from "@rev-robotics/rhsplib"; +import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; + +export async function digitalRead(channel: number): Promise { + let hubs = await openConnectedExpansionHubs(); + + await hubs[0].setDigitalDirection(channel, DIODirection.Input); + let state = await hubs[0].getDigitalSingleInput(channel); + + console.log(state); + + for (let hub of hubs) { + hub.close(); + } +} + +export async function digitalWrite(channel: number, state: boolean): Promise { + let hubs = await openConnectedExpansionHubs(); + + await hubs[0].setDigitalDirection(channel, DIODirection.Input); + await hubs[0].setDigitalSingleOutput(channel, state); + + for (let hub of hubs) { + hub.close(); + } +} diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index bf81c5d6..97d55fd1 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -19,6 +19,7 @@ import { openHubWithAddress, openParentExpansionHub, } from "@rev-robotics/expansion-hub"; +import { digitalRead, digitalWrite } from "./commands/digital.js"; const program = new Command(); @@ -33,6 +34,26 @@ program "module address. If this is specified, you must also specify a parent address", ); +let digitalCommand = program.command("digital"); + +digitalCommand + .command("write ") + .description("write digital pin") + .action(async (channel, state) => { + let channelNumber = Number(channel); + let stateValue = state == "high"; + + await digitalWrite(channelNumber, stateValue); + }); + +digitalCommand + .command("read ") + .description("read digital pin") + .action(async (channel) => { + let channelNumber = Number(channel); + await digitalRead(channelNumber); + }); + program .command("testErrorHandling") .description( From ca78fdc8d5cd8993775755e09010de099e410cab Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 18 May 2023 16:36:02 -0500 Subject: [PATCH 065/148] Add documentation --- packages/expansion-hub/src/ExpansionHub.ts | 39 ++++++++++++++-------- packages/sample/src/commands/digital.ts | 6 ++-- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/packages/expansion-hub/src/ExpansionHub.ts b/packages/expansion-hub/src/ExpansionHub.ts index a8578b42..23b291bf 100644 --- a/packages/expansion-hub/src/ExpansionHub.ts +++ b/packages/expansion-hub/src/ExpansionHub.ts @@ -1,19 +1,19 @@ import { BulkInputData, DebugGroup, - DIODirection, + DioDirection, I2CReadStatus, I2CSpeedCode, I2CWriteStatus, - LEDPattern, + LedPattern, ModuleInterface, ModuleStatus, - PIDCoefficients, - RGB, + PidCoefficients, + Rgb, VerbosityLevel, Version, } from "@rev-robotics/rhsplib"; -import { ParentRevHub, RevHub } from "./RevHub"; +import { ParentRevHub, RevHub } from "@rev-robotics/rev-hub-core"; export type ParentExpansionHub = ParentRevHub & ExpansionHub; @@ -36,9 +36,9 @@ export interface ExpansionHub extends RevHub { setNewModuleAddress(newModuleAddress: number): Promise; queryInterface(interfaceName: string): Promise; setModuleLedColor(red: number, green: number, blue: number): Promise; - getModuleLedColor(): Promise; - setModuleLedPattern(ledPattern: LEDPattern): Promise; - getModuleLedPattern(): Promise; + getModuleLedColor(): Promise; + setModuleLedPattern(ledPattern: LedPattern): Promise; + getModuleLedPattern(): Promise; setDebugLogLevel( debugGroup: DebugGroup, verbosityLevel: VerbosityLevel, @@ -59,9 +59,22 @@ export interface ExpansionHub extends RevHub { // DIO setDigitalSingleOutput(digitalChannel: number, value?: boolean): Promise; setDigitalAllOutputs(bitPackedField: number): Promise; - setDigitalDirection(digitalChannel: number, direction: DIODirection): Promise; - getDigitalDirection(digitalChannel: number): Promise; - getDigitalSingleInput(digitalChannel: number): Promise; + + /** + * Set a digital pin as input or output. + * @param dioPin + * @param direction + */ + setDigitalDirection(dioPin: number, direction: DioDirection): Promise; + getDigitalDirection(dioPin: number): Promise; + + /** + * Read the state of a given digital pin. + * Throws an error if the pin is not configured for input + * + * @param dioPin + */ + getDigitalSingleInput(dioPin: number): Promise; getDigitalAllInputs(): Promise; // I2C @@ -129,12 +142,12 @@ export interface ExpansionHub extends RevHub { setMotorPIDCoefficients( motorChannel: number, motorMode: number, - pid: PIDCoefficients, + pid: PidCoefficients, ): Promise; getMotorPIDCoefficients( motorChannel: number, motorMode: number, - ): Promise; + ): Promise; // Servo setServoConfiguration(servoChannel: number, framePeriod: number): Promise; diff --git a/packages/sample/src/commands/digital.ts b/packages/sample/src/commands/digital.ts index 5cd4a446..e22b560a 100644 --- a/packages/sample/src/commands/digital.ts +++ b/packages/sample/src/commands/digital.ts @@ -1,10 +1,10 @@ -import { DIODirection } from "@rev-robotics/rhsplib"; +import { DioDirection } from "@rev-robotics/rhsplib"; import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; export async function digitalRead(channel: number): Promise { let hubs = await openConnectedExpansionHubs(); - await hubs[0].setDigitalDirection(channel, DIODirection.Input); + await hubs[0].setDigitalDirection(channel, DioDirection.Input); let state = await hubs[0].getDigitalSingleInput(channel); console.log(state); @@ -17,7 +17,7 @@ export async function digitalRead(channel: number): Promise { export async function digitalWrite(channel: number, state: boolean): Promise { let hubs = await openConnectedExpansionHubs(); - await hubs[0].setDigitalDirection(channel, DIODirection.Input); + await hubs[0].setDigitalDirection(channel, DioDirection.Output); await hubs[0].setDigitalSingleOutput(channel, state); for (let hub of hubs) { From d95b0026d1b3ab9eb2686ff9237d4bb3df879c4a Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Mon, 22 May 2023 16:25:43 -0500 Subject: [PATCH 066/148] Document getDigitalAllInputs --- packages/expansion-hub/src/ExpansionHub.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/expansion-hub/src/ExpansionHub.ts b/packages/expansion-hub/src/ExpansionHub.ts index 23b291bf..a6509f82 100644 --- a/packages/expansion-hub/src/ExpansionHub.ts +++ b/packages/expansion-hub/src/ExpansionHub.ts @@ -75,6 +75,10 @@ export interface ExpansionHub extends RevHub { * @param dioPin */ getDigitalSingleInput(dioPin: number): Promise; + + /** + * Read all digital inputs as a bit-packed number. + */ getDigitalAllInputs(): Promise; // I2C From 660a0dfccff24843b4a937d28d3a5d8b9a88a035 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Mon, 22 May 2023 16:36:11 -0500 Subject: [PATCH 067/148] Fix missed merge conflict --- packages/sample/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/sample/package.json b/packages/sample/package.json index ed99554d..dcaf4c82 100644 --- a/packages/sample/package.json +++ b/packages/sample/package.json @@ -29,6 +29,7 @@ "list": "node dist/main.js list", "led": "node dist/main.js led", "motor": "node dist/main.js motor power 1 0.60", - "motor-position": "node dist/main.js --count 3000" + "motor-position": "node dist/main.js --count 3000", + "distance": "node dist/main.js distance 0" } } From f703a4552e84a268849e583ae6faa4aaa26dbf45 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 24 May 2023 09:53:59 -0500 Subject: [PATCH 068/148] Create type for digital state --- .../control-hub/src/internal/ControlHub.ts | 5 +- .../src/internal/ControlHubConnected.ts | 11 +- packages/core/src/ExpansionHub.ts | 5 +- packages/core/src/digital-state.ts | 20 +++ packages/core/src/index.ts | 1 + packages/expansion-hub/src/ExpansionHub.ts | 163 ------------------ .../src/internal/ExpansionHub.ts | 19 +- packages/sample/src/commands/digital.ts | 5 +- packages/sample/src/main.ts | 8 +- 9 files changed, 56 insertions(+), 181 deletions(-) create mode 100644 packages/core/src/digital-state.ts delete mode 100644 packages/expansion-hub/src/ExpansionHub.ts diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index bcf5d538..018ce192 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -5,6 +5,7 @@ import { BulkInputData, ControlHub, DebugGroup, + DigitalState, DioDirection, ExpansionHub, I2CReadStatus, @@ -238,7 +239,7 @@ export class ControlHubInternal implements ControlHub { return this.embedded.getDigitalDirection(dioPin); } - async getDigitalSingleInput(dioPin: number): Promise { + async getDigitalSingleInput(dioPin: number): Promise { return this.embedded.getDigitalSingleInput(dioPin); } @@ -411,7 +412,7 @@ export class ControlHubInternal implements ControlHub { return this.embedded.setDigitalDirection(dioPin, direction); } - async setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { + async setDigitalSingleOutput(dioPin: number, value: DigitalState): Promise { return this.embedded.setDigitalSingleOutput(dioPin, value); } diff --git a/packages/control-hub/src/internal/ControlHubConnected.ts b/packages/control-hub/src/internal/ControlHubConnected.ts index e349a121..c862ce9d 100644 --- a/packages/control-hub/src/internal/ControlHubConnected.ts +++ b/packages/control-hub/src/internal/ControlHubConnected.ts @@ -1,6 +1,7 @@ import { BulkInputData, DebugGroup, + DigitalState, DioDirection, ExpansionHub, I2CReadStatus, @@ -132,11 +133,13 @@ export class ControlHubConnected implements ParentExpansionHub { return isOutput ? DioDirection.Output : DioDirection.Input; } - async getDigitalSingleInput(dioPin: number): Promise { - return await this.sendCommand("getDigitalInput", { + async getDigitalSingleInput(dioPin: number): Promise { + let result: boolean = await this.sendCommand("getDigitalInput", { id: this.id, digitalChannel: dioPin, }); + + return result ? DigitalState.High : DigitalState.Low; } async getFTDIResetControl(): Promise { @@ -417,11 +420,11 @@ export class ControlHubConnected implements ParentExpansionHub { }); } - async setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { + async setDigitalSingleOutput(dioPin: number, value: DigitalState): Promise { await this.sendCommand("readVersionString", { id: this.id, digitalChannel: dioPin, - value: value ?? false, + value: value.isHigh(), }); } diff --git a/packages/core/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts index a1ba08ea..3749f36f 100644 --- a/packages/core/src/ExpansionHub.ts +++ b/packages/core/src/ExpansionHub.ts @@ -13,6 +13,7 @@ import { I2CWriteStatus } from "./I2CWriteStatus.js"; import { I2CReadStatus } from "./I2CReadStatus.js"; import { PidCoefficients } from "./PidCoefficients.js"; import { MotorMode } from "./MotorMode.js"; +import { DigitalState } from "./digital-state.js"; export type ParentExpansionHub = ParentRevHub & ExpansionHub; @@ -105,11 +106,11 @@ export interface ExpansionHub extends RevHub { getFTDIResetControl(): Promise; // DIO - setDigitalSingleOutput(dioPin: number, value?: boolean): Promise; + setDigitalSingleOutput(dioPin: number, value: DigitalState): Promise; setDigitalAllOutputs(bitPackedField: number): Promise; setDigitalDirection(dioPin: number, direction: DioDirection): Promise; getDigitalDirection(dioPin: number): Promise; - getDigitalSingleInput(dioPin: number): Promise; + getDigitalSingleInput(dioPin: number): Promise; getDigitalAllInputs(): Promise; // I2C diff --git a/packages/core/src/digital-state.ts b/packages/core/src/digital-state.ts new file mode 100644 index 00000000..9bffb614 --- /dev/null +++ b/packages/core/src/digital-state.ts @@ -0,0 +1,20 @@ +export class DigitalState { + static High = new DigitalState(true); + static Low = new DigitalState(false); + + private readonly state: boolean; + private constructor(state: boolean) { + this.state = state; + } + isHigh(): boolean { + return this.state; + } + + isLow(): boolean { + return !this.state; + } + + toString(): string { + return this.state ? "High" : "Low"; + } +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 5e8719ee..544285b9 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -3,6 +3,7 @@ export * from "./ControlHub.js"; export * from "./RevHub.js"; export * from "./RevHubType.js"; export * from "./BulkInputData.js"; +export * from "./digital-state.js"; export * from "./DebugGroup.js"; export * from "./DioDirection.js"; export * from "./DiscoveredAddresses.js"; diff --git a/packages/expansion-hub/src/ExpansionHub.ts b/packages/expansion-hub/src/ExpansionHub.ts deleted file mode 100644 index a6509f82..00000000 --- a/packages/expansion-hub/src/ExpansionHub.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { - BulkInputData, - DebugGroup, - DioDirection, - I2CReadStatus, - I2CSpeedCode, - I2CWriteStatus, - LedPattern, - ModuleInterface, - ModuleStatus, - PidCoefficients, - Rgb, - VerbosityLevel, - Version, -} from "@rev-robotics/rhsplib"; -import { ParentRevHub, RevHub } from "@rev-robotics/rev-hub-core"; - -export type ParentExpansionHub = ParentRevHub & ExpansionHub; - -export interface ExpansionHub extends RevHub { - readonly isOpen: boolean; - responseTimeoutMs: number; - - /** - * Closes this hub and releases any resources bound to it. - * If this hub is a parent hub, the serial port will be closed - * and all children will be closed as well. Do not use this hub after - * it has been closed. - */ - close(): void; - sendWriteCommand(packetTypeID: number, payload: number[]): Promise; - sendReadCommand(packetTypeID: number, payload: number[]): Promise; - getModuleStatus(clearStatusAfterResponse: boolean): Promise; - sendKeepAlive(): Promise; - sendFailSafe(): Promise; - setNewModuleAddress(newModuleAddress: number): Promise; - queryInterface(interfaceName: string): Promise; - setModuleLedColor(red: number, green: number, blue: number): Promise; - getModuleLedColor(): Promise; - setModuleLedPattern(ledPattern: LedPattern): Promise; - getModuleLedPattern(): Promise; - setDebugLogLevel( - debugGroup: DebugGroup, - verbosityLevel: VerbosityLevel, - ): Promise; - getInterfacePacketID(interfaceName: string, functionNumber: number): Promise; - - // Device Control - getBulkInputData(): Promise; - getADC(): Promise; - setPhoneChargeControl(chargeEnable: boolean): Promise; - getPhoneChargeControl(): Promise; - injectDataLogHint(hintText: string): Promise; - readVersionString(): Promise; - readVersion(): Promise; - setFTDIResetControl(ftdiResetControl: boolean): Promise; - getFTDIResetControl(): Promise; - - // DIO - setDigitalSingleOutput(digitalChannel: number, value?: boolean): Promise; - setDigitalAllOutputs(bitPackedField: number): Promise; - - /** - * Set a digital pin as input or output. - * @param dioPin - * @param direction - */ - setDigitalDirection(dioPin: number, direction: DioDirection): Promise; - getDigitalDirection(dioPin: number): Promise; - - /** - * Read the state of a given digital pin. - * Throws an error if the pin is not configured for input - * - * @param dioPin - */ - getDigitalSingleInput(dioPin: number): Promise; - - /** - * Read all digital inputs as a bit-packed number. - */ - getDigitalAllInputs(): Promise; - - // I2C - setI2CChannelConfiguration( - i2cChannel: number, - speedCode: I2CSpeedCode, - ): Promise; - getI2CChannelConfiguration(i2cChannel: number): Promise; - writeI2CSingleByte( - i2cChannel: number, - slaveAddress: number, - byte: number, - ): Promise; - writeI2CMultipleBytes( - i2cChannel: number, - slaveAddress: number, - bytes: number[], - ): Promise; - getI2CWriteStatus(i2cChannel: number): Promise; - readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise; - readI2CMultipleBytes( - i2cChannel: number, - slaveAddress: number, - numBytesToRead: number, - ): Promise; - writeI2CReadMultipleBytes( - i2cChannel: number, - slaveAddress: number, - numBytesToRead: number, - startAddress: number, - ): Promise; - getI2CReadStatus(i2cChannel: number): Promise; - - // Motor - setMotorChannelMode( - motorChannel: number, - motorMode: number, - floatAtZero: boolean, - ): Promise; - getMotorChannelMode( - motorChannel: number, - ): Promise<{ motorMode: number; floatAtZero: boolean }>; - setMotorChannelEnable(motorChannel: number, enable: boolean): Promise; - getMotorChannelEnable(motorChannel: number): Promise; - setMotorChannelCurrentAlertLevel( - motorChannel: number, - currentLimit_mA: number, - ): Promise; - getMotorChannelCurrentAlertLevel(motorChannel: number): Promise; - resetMotorEncoder(motorChannel: number): Promise; - setMotorConstantPower(motorChannel: number, powerLevel: number): Promise; - getMotorConstantPower(motorChannel: number): Promise; - setMotorTargetVelocity(motorChannel: number, velocity_cps: number): Promise; - getMotorTargetVelocity(motorChannel: number): Promise; - setMotorTargetPosition( - motorChannel: number, - targetPosition_counts: number, - targetTolerance_counts: number, - ): Promise; - getMotorTargetPosition( - motorChannel: number, - ): Promise<{ targetPosition: number; targetTolerance: number }>; - getMotorAtTarget(motorChannel: number): Promise; - getMotorEncoderPosition(motorChannel: number): Promise; - setMotorPIDCoefficients( - motorChannel: number, - motorMode: number, - pid: PidCoefficients, - ): Promise; - getMotorPIDCoefficients( - motorChannel: number, - motorMode: number, - ): Promise; - - // Servo - setServoConfiguration(servoChannel: number, framePeriod: number): Promise; - getServoConfiguration(servoChannel: number): Promise; - setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise; - getServoPulseWidth(servoChannel: number): Promise; - setServoEnable(servoChannel: number, enable: boolean): Promise; - getServoEnable(servoChannel: number): Promise; -} diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index 26950b59..1c557ff4 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -1,4 +1,9 @@ -import { ExpansionHub, ParentRevHub, RevHub } from "@rev-robotics/rev-hub-core"; +import { + DigitalState, + ExpansionHub, + ParentRevHub, + RevHub, +} from "@rev-robotics/rev-hub-core"; import { NativeRevHub, Serial as SerialPort, @@ -190,9 +195,11 @@ export class ExpansionHubInternal implements ExpansionHub { }); } - getDigitalSingleInput(dioPin: number): Promise { - return this.convertErrorPromise(() => { - return this.nativeRevHub.getDigitalSingleInput(dioPin); + async getDigitalSingleInput(dioPin: number): Promise { + return this.convertErrorPromise(async () => { + return (await this.nativeRevHub.getDigitalSingleInput(dioPin)) + ? DigitalState.High + : DigitalState.Low; }); } @@ -446,9 +453,9 @@ export class ExpansionHubInternal implements ExpansionHub { }); } - setDigitalSingleOutput(dioPin: number, value?: boolean): Promise { + setDigitalSingleOutput(dioPin: number, value: DigitalState): Promise { return this.convertErrorPromise(() => { - return this.nativeRevHub.setDigitalSingleOutput(dioPin, value); + return this.nativeRevHub.setDigitalSingleOutput(dioPin, value.isHigh()); }); } diff --git a/packages/sample/src/commands/digital.ts b/packages/sample/src/commands/digital.ts index e22b560a..0678376b 100644 --- a/packages/sample/src/commands/digital.ts +++ b/packages/sample/src/commands/digital.ts @@ -1,5 +1,6 @@ import { DioDirection } from "@rev-robotics/rhsplib"; import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; +import { DigitalState } from "@rev-robotics/rev-hub-core"; export async function digitalRead(channel: number): Promise { let hubs = await openConnectedExpansionHubs(); @@ -7,14 +8,14 @@ export async function digitalRead(channel: number): Promise { await hubs[0].setDigitalDirection(channel, DioDirection.Input); let state = await hubs[0].getDigitalSingleInput(channel); - console.log(state); + console.log(`${state}`); for (let hub of hubs) { hub.close(); } } -export async function digitalWrite(channel: number, state: boolean): Promise { +export async function digitalWrite(channel: number, state: DigitalState): Promise { let hubs = await openConnectedExpansionHubs(); await hubs[0].setDigitalDirection(channel, DioDirection.Output); diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 97d55fd1..6a246c99 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -12,7 +12,11 @@ import { list } from "./command/list.js"; import { led } from "./command/led.js"; import { runServo } from "./command/servo.js"; import { openUsbControlHubs } from "./adb-setup.js"; -import { ExpansionHub, ParentExpansionHub } from "@rev-robotics/rev-hub-core"; +import { + DigitalState, + ExpansionHub, + ParentExpansionHub, +} from "@rev-robotics/rev-hub-core"; import { getPossibleExpansionHubSerialNumbers, openConnectedExpansionHubs, @@ -41,7 +45,7 @@ digitalCommand .description("write digital pin") .action(async (channel, state) => { let channelNumber = Number(channel); - let stateValue = state == "high"; + let stateValue = state == "high" ? DigitalState.High : DigitalState.Low; await digitalWrite(channelNumber, stateValue); }); From 64b740af308bfda4df57607e197cc36a4c76e254 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 24 May 2023 15:30:57 -0500 Subject: [PATCH 069/148] Make High and Low readonly --- packages/core/src/digital-state.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/digital-state.ts b/packages/core/src/digital-state.ts index 9bffb614..6b5049f3 100644 --- a/packages/core/src/digital-state.ts +++ b/packages/core/src/digital-state.ts @@ -1,6 +1,6 @@ export class DigitalState { - static High = new DigitalState(true); - static Low = new DigitalState(false); + static readonly High = new DigitalState(true); + static readonly Low = new DigitalState(false); private readonly state: boolean; private constructor(state: boolean) { From 949beb4675458ee99e4e20bbe1c6bebba3903bbf Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 24 May 2023 15:38:05 -0500 Subject: [PATCH 070/148] Create DigitalChannelDirection type --- packages/core/src/DigitalChannelDirection.ts | 4 +++ packages/core/src/index.ts | 1 + .../src/internal/ExpansionHub.ts | 30 +++++++++++++------ 3 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 packages/core/src/DigitalChannelDirection.ts diff --git a/packages/core/src/DigitalChannelDirection.ts b/packages/core/src/DigitalChannelDirection.ts new file mode 100644 index 00000000..b57639ad --- /dev/null +++ b/packages/core/src/DigitalChannelDirection.ts @@ -0,0 +1,4 @@ +export enum DigitalChannelDirection { + Input, + Output, +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 544285b9..3fdd1efc 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -4,6 +4,7 @@ export * from "./RevHub.js"; export * from "./RevHubType.js"; export * from "./BulkInputData.js"; export * from "./digital-state.js"; +export * from "./DigitalChannelDirection.js"; export * from "./DebugGroup.js"; export * from "./DioDirection.js"; export * from "./DiscoveredAddresses.js"; diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index 1c557ff4..c411c72f 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -1,4 +1,5 @@ import { + DigitalChannelDirection, DigitalState, ExpansionHub, ParentRevHub, @@ -189,15 +190,18 @@ export class ExpansionHubInternal implements ExpansionHub { }); } - getDigitalDirection(dioPin: number): Promise { - return this.convertErrorPromise(() => { - return this.nativeRevHub.getDigitalDirection(dioPin); + getDigitalDirection(digitalChannel: number): Promise { + return this.convertErrorPromise(async () => { + return (await this.nativeRevHub.getDigitalDirection(digitalChannel)) == + DioDirection.Input + ? DioDirection.Input + : DioDirection.Output; }); } - async getDigitalSingleInput(dioPin: number): Promise { + async getDigitalSingleInput(digitalChannel: number): Promise { return this.convertErrorPromise(async () => { - return (await this.nativeRevHub.getDigitalSingleInput(dioPin)) + return (await this.nativeRevHub.getDigitalSingleInput(digitalChannel)) ? DigitalState.High : DigitalState.Low; }); @@ -447,15 +451,23 @@ export class ExpansionHubInternal implements ExpansionHub { }); } - setDigitalDirection(dioPin: number, direction: DioDirection): Promise { + setDigitalDirection(digitalChannel: number, direction: DioDirection): Promise { return this.convertErrorPromise(() => { - return this.nativeRevHub.setDigitalDirection(dioPin, direction); + return this.nativeRevHub.setDigitalDirection( + digitalChannel, + direction == DioDirection.Input + ? DioDirection.Input + : DioDirection.Output, + ); }); } - setDigitalSingleOutput(dioPin: number, value: DigitalState): Promise { + setDigitalSingleOutput(digitalChannel: number, value: DigitalState): Promise { return this.convertErrorPromise(() => { - return this.nativeRevHub.setDigitalSingleOutput(dioPin, value.isHigh()); + return this.nativeRevHub.setDigitalSingleOutput( + digitalChannel, + value.isHigh(), + ); }); } From bac4567de3f9d587c25f835939593c27f1ef1cdc Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 24 May 2023 15:44:12 -0500 Subject: [PATCH 071/148] Rename digital methods --- packages/control-hub/src/internal/ControlHub.ts | 16 ++++++++-------- .../src/internal/ControlHubConnected.ts | 8 ++++---- packages/core/src/ExpansionHub.ts | 8 ++++---- .../expansion-hub/src/internal/ExpansionHub.ts | 8 ++++---- packages/sample/src/commands/digital.ts | 6 +++--- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 018ce192..1a6ef7ed 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -231,16 +231,16 @@ export class ControlHubInternal implements ControlHub { return this.embedded.getBulkInputData(); } - async getDigitalAllInputs(): Promise { - return this.embedded.getDigitalAllInputs(); + async getAllDigitalInputs(): Promise { + return this.embedded.getAllDigitalInputs(); } async getDigitalDirection(dioPin: number): Promise { return this.embedded.getDigitalDirection(dioPin); } - async getDigitalSingleInput(dioPin: number): Promise { - return this.embedded.getDigitalSingleInput(dioPin); + async getDigitalInput(dioPin: number): Promise { + return this.embedded.getDigitalInput(dioPin); } async getFTDIResetControl(): Promise { @@ -404,16 +404,16 @@ export class ControlHubInternal implements ControlHub { return this.embedded.setDebugLogLevel(debugGroup, verbosityLevel); } - async setDigitalAllOutputs(bitPackedField: number): Promise { - return this.embedded.setDigitalAllOutputs(bitPackedField); + async setAllDigitalOutputs(bitPackedField: number): Promise { + return this.embedded.setAllDigitalOutputs(bitPackedField); } async setDigitalDirection(dioPin: number, direction: DioDirection): Promise { return this.embedded.setDigitalDirection(dioPin, direction); } - async setDigitalSingleOutput(dioPin: number, value: DigitalState): Promise { - return this.embedded.setDigitalSingleOutput(dioPin, value); + async setDigitalOutput(dioPin: number, value: DigitalState): Promise { + return this.embedded.setDigitalOutput(dioPin, value); } async setFTDIResetControl(ftdiResetControl: boolean): Promise { diff --git a/packages/control-hub/src/internal/ControlHubConnected.ts b/packages/control-hub/src/internal/ControlHubConnected.ts index c862ce9d..54f881e1 100644 --- a/packages/control-hub/src/internal/ControlHubConnected.ts +++ b/packages/control-hub/src/internal/ControlHubConnected.ts @@ -118,7 +118,7 @@ export class ControlHubConnected implements ParentExpansionHub { }); } - async getDigitalAllInputs(): Promise { + async getAllDigitalInputs(): Promise { return await this.sendCommand("getAllDigitalInputs", { id: this.id, }); @@ -133,7 +133,7 @@ export class ControlHubConnected implements ParentExpansionHub { return isOutput ? DioDirection.Output : DioDirection.Input; } - async getDigitalSingleInput(dioPin: number): Promise { + async getDigitalInput(dioPin: number): Promise { let result: boolean = await this.sendCommand("getDigitalInput", { id: this.id, digitalChannel: dioPin, @@ -405,7 +405,7 @@ export class ControlHubConnected implements ParentExpansionHub { }); } - async setDigitalAllOutputs(bitPackedField: number): Promise { + async setAllDigitalOutputs(bitPackedField: number): Promise { await this.sendCommand("readVersionString", { id: this.id, bitField: bitPackedField, @@ -420,7 +420,7 @@ export class ControlHubConnected implements ParentExpansionHub { }); } - async setDigitalSingleOutput(dioPin: number, value: DigitalState): Promise { + async setDigitalOutput(dioPin: number, value: DigitalState): Promise { await this.sendCommand("readVersionString", { id: this.id, digitalChannel: dioPin, diff --git a/packages/core/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts index 3749f36f..7f9a602f 100644 --- a/packages/core/src/ExpansionHub.ts +++ b/packages/core/src/ExpansionHub.ts @@ -106,12 +106,12 @@ export interface ExpansionHub extends RevHub { getFTDIResetControl(): Promise; // DIO - setDigitalSingleOutput(dioPin: number, value: DigitalState): Promise; - setDigitalAllOutputs(bitPackedField: number): Promise; + setDigitalOutput(dioPin: number, value: DigitalState): Promise; + setAllDigitalOutputs(bitPackedField: number): Promise; setDigitalDirection(dioPin: number, direction: DioDirection): Promise; getDigitalDirection(dioPin: number): Promise; - getDigitalSingleInput(dioPin: number): Promise; - getDigitalAllInputs(): Promise; + getDigitalInput(dioPin: number): Promise; + getAllDigitalInputs(): Promise; // I2C setI2CChannelConfiguration( diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index c411c72f..7533f0a3 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -184,7 +184,7 @@ export class ExpansionHubInternal implements ExpansionHub { }); } - getDigitalAllInputs(): Promise { + getAllDigitalInputs(): Promise { return this.convertErrorPromise(() => { return this.nativeRevHub.getDigitalAllInputs(); }); @@ -199,7 +199,7 @@ export class ExpansionHubInternal implements ExpansionHub { }); } - async getDigitalSingleInput(digitalChannel: number): Promise { + async getDigitalInput(digitalChannel: number): Promise { return this.convertErrorPromise(async () => { return (await this.nativeRevHub.getDigitalSingleInput(digitalChannel)) ? DigitalState.High @@ -445,7 +445,7 @@ export class ExpansionHubInternal implements ExpansionHub { this.nativeRevHub.setDestAddress(destAddress); } - setDigitalAllOutputs(bitPackedField: number): Promise { + setAllDigitalOutputs(bitPackedField: number): Promise { return this.convertErrorPromise(() => { return this.nativeRevHub.setDigitalAllOutputs(bitPackedField); }); @@ -462,7 +462,7 @@ export class ExpansionHubInternal implements ExpansionHub { }); } - setDigitalSingleOutput(digitalChannel: number, value: DigitalState): Promise { + setDigitalOutput(digitalChannel: number, value: DigitalState): Promise { return this.convertErrorPromise(() => { return this.nativeRevHub.setDigitalSingleOutput( digitalChannel, diff --git a/packages/sample/src/commands/digital.ts b/packages/sample/src/commands/digital.ts index 0678376b..aeb77193 100644 --- a/packages/sample/src/commands/digital.ts +++ b/packages/sample/src/commands/digital.ts @@ -6,7 +6,7 @@ export async function digitalRead(channel: number): Promise { let hubs = await openConnectedExpansionHubs(); await hubs[0].setDigitalDirection(channel, DioDirection.Input); - let state = await hubs[0].getDigitalSingleInput(channel); + let state = await hubs[0].getDigitalInput(channel); console.log(`${state}`); @@ -18,8 +18,8 @@ export async function digitalRead(channel: number): Promise { export async function digitalWrite(channel: number, state: DigitalState): Promise { let hubs = await openConnectedExpansionHubs(); - await hubs[0].setDigitalDirection(channel, DioDirection.Output); - await hubs[0].setDigitalSingleOutput(channel, state); + await hubs[0].setDigitalDirection(channel, DioDirection.Input); + await hubs[0].setDigitalOutput(channel, state); for (let hub of hubs) { hub.close(); From aa4ad58a689b6d4a654060aa2919e5e6d7ab36f8 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 09:52:27 -0500 Subject: [PATCH 072/148] Error out if user provides anything other than high, low, 0, or 1 --- packages/sample/src/main.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 6a246c99..6808266a 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -45,9 +45,17 @@ digitalCommand .description("write digital pin") .action(async (channel, state) => { let channelNumber = Number(channel); - let stateValue = state == "high" ? DigitalState.High : DigitalState.Low; + let stateBoolean = false; + if (state === "high" || state === "1") { + stateBoolean = true; + } else if (state === "low" || state === "0") { + stateBoolean = false; + } else { + program.error("Please provide only one of {high, low, 1, 0}"); + } + let digitalState = stateBoolean ? DigitalState.High : DigitalState.Low; - await digitalWrite(channelNumber, stateValue); + await digitalWrite(channelNumber, digitalState); }); digitalCommand From 4c1d6924a5b8ae0d33b2fb645a303f3854179cc7 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 09:54:47 -0500 Subject: [PATCH 073/148] Set direction correctly for write --- packages/sample/src/commands/digital.ts | 2 +- packages/sample/src/main.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sample/src/commands/digital.ts b/packages/sample/src/commands/digital.ts index aeb77193..ce9859f8 100644 --- a/packages/sample/src/commands/digital.ts +++ b/packages/sample/src/commands/digital.ts @@ -18,7 +18,7 @@ export async function digitalRead(channel: number): Promise { export async function digitalWrite(channel: number, state: DigitalState): Promise { let hubs = await openConnectedExpansionHubs(); - await hubs[0].setDigitalDirection(channel, DioDirection.Input); + await hubs[0].setDigitalDirection(channel, DioDirection.Output); await hubs[0].setDigitalOutput(channel, state); for (let hub of hubs) { diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 6808266a..cf2c7d79 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -42,7 +42,7 @@ let digitalCommand = program.command("digital"); digitalCommand .command("write ") - .description("write digital pin") + .description("write digital pin. Valid values for are high, low, 0, and 1.") .action(async (channel, state) => { let channelNumber = Number(channel); let stateBoolean = false; From 2c047322e0c79b367bd982e7dae223027d6ad150 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 10:06:21 -0500 Subject: [PATCH 074/148] Add continuous flag --- packages/sample/src/commands/digital.ts | 13 ++++++++++--- packages/sample/src/main.ts | 7 +++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/sample/src/commands/digital.ts b/packages/sample/src/commands/digital.ts index ce9859f8..1c054dce 100644 --- a/packages/sample/src/commands/digital.ts +++ b/packages/sample/src/commands/digital.ts @@ -2,13 +2,20 @@ import { DioDirection } from "@rev-robotics/rhsplib"; import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; import { DigitalState } from "@rev-robotics/rev-hub-core"; -export async function digitalRead(channel: number): Promise { +export async function digitalRead(channel: number, continuous: boolean): Promise { let hubs = await openConnectedExpansionHubs(); await hubs[0].setDigitalDirection(channel, DioDirection.Input); - let state = await hubs[0].getDigitalInput(channel); - console.log(`${state}`); + if (continuous) { + while (true) { + let state = await hubs[0].getDigitalInput(channel); + console.log(`${state}`); + } + } else { + let state = await hubs[0].getDigitalInput(channel); + console.log(`${state}`); + } for (let hub of hubs) { hub.close(); diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index cf2c7d79..26192cd3 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -60,10 +60,13 @@ digitalCommand digitalCommand .command("read ") + .option("--continuous", "run continuously") .description("read digital pin") - .action(async (channel) => { + .action(async (channel, options) => { + let isContinuous = options.continuous !== undefined; let channelNumber = Number(channel); - await digitalRead(channelNumber); + + await digitalRead(channelNumber, isContinuous); }); program From 5d25f1caabe4998473634abe981868e30e0b7040 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 7 Jun 2023 11:50:05 -0500 Subject: [PATCH 075/148] depend on specific version of expansion hub --- package-lock.json | 10 +++++----- packages/control-hub/package.json | 2 +- packages/sample/package.json | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index b383a5bb..a8913c33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7807,7 +7807,7 @@ }, "packages/control-hub": { "name": "@rev-robotics/control-hub", - "version": "0.1.0", + "version": "1.0.0", "dependencies": { "@rev-robotics/rev-hub-core": "*", "axios": "^1.4.0", @@ -7862,8 +7862,8 @@ "name": "rev-hub-cli", "version": "1.0.0", "dependencies": { - "@rev-robotics/control-hub": "*", - "@rev-robotics/expansion-hub": "*", + "@rev-robotics/control-hub": "1.0.0", + "@rev-robotics/expansion-hub": "1.0.0", "@u4/adbkit": "^4.1.19", "commander": "^10.0.1", "get-port": "^6.1.2", @@ -12411,8 +12411,8 @@ "rev-hub-cli": { "version": "file:packages/sample", "requires": { - "@rev-robotics/control-hub": "*", - "@rev-robotics/expansion-hub": "*", + "@rev-robotics/control-hub": "1.0.0", + "@rev-robotics/expansion-hub": "1.0.0", "@types/debug": "^4.1.8", "@types/node-forge": "^1.3.2", "@types/ws": "^8.5.4", diff --git a/packages/control-hub/package.json b/packages/control-hub/package.json index fe6018ac..eb7ea0f0 100644 --- a/packages/control-hub/package.json +++ b/packages/control-hub/package.json @@ -1,6 +1,6 @@ { "name": "@rev-robotics/control-hub", - "version": "0.1.0", + "version": "1.0.0", "description": "High level library for the REV Robotics Control Hub", "main": "dist/index.js", "type": "module", diff --git a/packages/sample/package.json b/packages/sample/package.json index dcaf4c82..b5541866 100644 --- a/packages/sample/package.json +++ b/packages/sample/package.json @@ -7,8 +7,8 @@ "private": true, "type": "module", "dependencies": { - "@rev-robotics/control-hub": "*", - "@rev-robotics/expansion-hub": "*", + "@rev-robotics/control-hub": "1.0.0", + "@rev-robotics/expansion-hub": "1.0.0", "ws": "8.13.0", "commander": "^10.0.1", "@u4/adbkit": "^4.1.19", From cb0beb5db8a084749a8a47634272fa5e1c3733be Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 8 Jun 2023 15:23:45 -0500 Subject: [PATCH 076/148] Add documentation --- packages/core/src/ExpansionHub.ts | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/packages/core/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts index 7f9a602f..d7007c25 100644 --- a/packages/core/src/ExpansionHub.ts +++ b/packages/core/src/ExpansionHub.ts @@ -108,9 +108,31 @@ export interface ExpansionHub extends RevHub { // DIO setDigitalOutput(dioPin: number, value: DigitalState): Promise; setAllDigitalOutputs(bitPackedField: number): Promise; - setDigitalDirection(dioPin: number, direction: DioDirection): Promise; - getDigitalDirection(dioPin: number): Promise; - getDigitalInput(dioPin: number): Promise; + + /** + * Set a digital pin as input or output. + * @param digitalChannel + * @param direction + */ + setDigitalDirection(digitalChannel: number, direction: DioDirection): Promise; + + /** + * Get the Input/Output direction of a digital channel + * @param digitalChannel + */ + getDigitalDirection(digitalChannel: number): Promise; + + /** + * Read the state of a given digital pin. + * Throws an error if the pin is not configured for input + * + * @param digitalChannel + */ + getDigitalInput(digitalChannel: number): Promise; + + /** + * Read all digital inputs as a bit-packed number. + */ getAllDigitalInputs(): Promise; // I2C From 99a8f9d13d37096013e314e9d764e78917ea3a42 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 17 May 2023 13:09:05 -0500 Subject: [PATCH 077/148] Add module for distance sensor --- package-lock.json | 25 ++ packages/distance-sensor/package.json | 18 + .../distance-sensor/src/distance-sensor.ts | 392 ++++++++++++++++++ packages/distance-sensor/src/i2c-utils.ts | 85 ++++ packages/distance-sensor/src/index.ts | 1 + packages/distance-sensor/tsconfig.json | 7 + 6 files changed, 528 insertions(+) create mode 100644 packages/distance-sensor/package.json create mode 100644 packages/distance-sensor/src/distance-sensor.ts create mode 100644 packages/distance-sensor/src/i2c-utils.ts create mode 100644 packages/distance-sensor/src/index.ts create mode 100644 packages/distance-sensor/tsconfig.json diff --git a/package-lock.json b/package-lock.json index a8913c33..7781c0cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1832,6 +1832,10 @@ "resolved": "packages/control-hub", "link": true }, + "node_modules/@rev-robotics/distance-sensor": { + "resolved": "packages/distance-sensor", + "link": true + }, "node_modules/@rev-robotics/expansion-hub": { "resolved": "packages/expansion-hub", "link": true @@ -7828,6 +7832,18 @@ "typescript": "^5.0.2" } }, + "packages/distance-sensor": { + "name": "@rev-robotics/distance-sensor", + "version": "0.1.0", + "dependencies": { + "@rev-robotics/expansion-hub": "*", + "serialport": "^10.5.0" + }, + "devDependencies": { + "@types/node": "^16.18.18", + "typescript": "^5.0.2" + } + }, "packages/expansion-hub": { "name": "@rev-robotics/expansion-hub", "version": "1.0.0", @@ -9193,6 +9209,15 @@ "typescript": "^5.0.2" } }, + "@rev-robotics/distance-sensor": { + "version": "file:packages/distance-sensor", + "requires": { + "@rev-robotics/expansion-hub": "*", + "@types/node": "^16.18.18", + "serialport": "^10.5.0", + "typescript": "^5.0.2" + } + }, "@rev-robotics/expansion-hub": { "version": "file:packages/expansion-hub", "requires": { diff --git a/packages/distance-sensor/package.json b/packages/distance-sensor/package.json new file mode 100644 index 00000000..4cf357fc --- /dev/null +++ b/packages/distance-sensor/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rev-robotics/distance-sensor", + "version": "0.1.0", + "description": "Library for using the REV Robotics 2m distance sensor", + "main": "dist/index.js", + "type": "module", + "dependencies": { + "serialport": "^10.5.0", + "@rev-robotics/expansion-hub": "*" + }, + "devDependencies": { + "@types/node": "^16.18.18", + "typescript": "^5.0.2" + }, + "scripts": { + "build": "tsc" + } +} \ No newline at end of file diff --git a/packages/distance-sensor/src/distance-sensor.ts b/packages/distance-sensor/src/distance-sensor.ts new file mode 100644 index 00000000..59e960ea --- /dev/null +++ b/packages/distance-sensor/src/distance-sensor.ts @@ -0,0 +1,392 @@ +import { + readRegister, + readRegisterMultipleBytes, + readShort, + writeRegister, + writeRegisterMultipleBytes, + writeShort, +} from "./i2c-utils.js"; +import { ExpansionHub } from "@rev-robotics/rev-hub-core"; + +export class DistanceSensor { + constructor(hub: ExpansionHub, channel: number) { + this.hub = hub; + this.channel = channel; + } + + private readonly hub: ExpansionHub; + private readonly channel: number; + private address: number = 0x52 / 2; + private spadCount = 0; + private spadTypeIsAperture = false; + + async is2mDistanceSensor(): Promise { + if ((await this.readRegister(0xc0)) != 0xee) return false; + if ((await this.readRegister(0xc1)) != 0xaa) return false; + if ((await this.readRegister(0xc2)) != 0x10) return false; + if ((await this.readRegister(0x61)) != 0x00) return false; + else return true; + } + + async initialize() { + await this.writeRegister(0x88, 0x00); + await this.writeRegister(0x80, 0x01); + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x00, 0x00); + + let stopValue = await this.readRegister(0x91); + + await this.writeRegister(0x00, 0x01); + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x80, 0x00); + + let msgConfigControl = (await this.readRegister(0x60)) | 0x12; + await this.writeRegister(0x60, msgConfigControl); + + await this.setSignalRateLimit(0.25); + + await this.writeRegister(0x01, 0xff); + + await this.getSpadInfo(); + + let refSpadMap = await this.readMultipleBytes(0xb0, 6); + + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x4f, 0x00); + await this.writeRegister(0x4e, 0x2c); + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0xb6, 0xb4); + + let firstSpadToEnable = this.spadTypeIsAperture ? 12 : 0; + let spadsEnabled = 0; + + for (let i = 0; i < 48; i++) { + if (i < firstSpadToEnable || spadsEnabled == this.spadCount) { + refSpadMap[i / 8] &= ~(1 << i % 8); + } else if (((refSpadMap[i / 8] >> i % 8) & 0x01) != 0) { + spadsEnabled++; + } + } + + console.log(refSpadMap); + + //begin load tuning settings + await this.writeMultipleBytes(0xb0, refSpadMap); + + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x00, 0x00); + + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x09, 0x00); + await this.writeRegister(0x10, 0x00); + await this.writeRegister(0x11, 0x00); + + await this.writeRegister(0x24, 0x01); + await this.writeRegister(0x25, 0xff); + await this.writeRegister(0x75, 0x00); + + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x4e, 0x2c); + await this.writeRegister(0x48, 0x00); + await this.writeRegister(0x30, 0x20); + + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x30, 0x09); + await this.writeRegister(0x54, 0x00); + await this.writeRegister(0x31, 0x04); + await this.writeRegister(0x32, 0x03); + await this.writeRegister(0x40, 0x83); + await this.writeRegister(0x46, 0x25); + await this.writeRegister(0x60, 0x00); + await this.writeRegister(0x27, 0x00); + await this.writeRegister(0x50, 0x06); + await this.writeRegister(0x51, 0x00); + await this.writeRegister(0x52, 0x96); + await this.writeRegister(0x56, 0x08); + await this.writeRegister(0x57, 0x30); + await this.writeRegister(0x61, 0x00); + await this.writeRegister(0x62, 0x00); + await this.writeRegister(0x64, 0x00); + await this.writeRegister(0x65, 0x00); + await this.writeRegister(0x66, 0xa0); + + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x22, 0x32); + await this.writeRegister(0x47, 0x14); + await this.writeRegister(0x49, 0xff); + await this.writeRegister(0x4a, 0x00); + + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x7a, 0x0a); + await this.writeRegister(0x7b, 0x00); + await this.writeRegister(0x78, 0x21); + + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x23, 0x34); + await this.writeRegister(0x42, 0x00); + await this.writeRegister(0x44, 0xff); + await this.writeRegister(0x45, 0x26); + await this.writeRegister(0x46, 0x05); + await this.writeRegister(0x40, 0x40); + await this.writeRegister(0x0e, 0x06); + await this.writeRegister(0x20, 0x1a); + await this.writeRegister(0x43, 0x40); + + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x34, 0x03); + await this.writeRegister(0x35, 0x44); + + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x31, 0x04); + await this.writeRegister(0x4b, 0x09); + await this.writeRegister(0x4c, 0x05); + await this.writeRegister(0x4d, 0x04); + + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x44, 0x00); + await this.writeRegister(0x45, 0x20); + await this.writeRegister(0x47, 0x08); + await this.writeRegister(0x48, 0x28); + await this.writeRegister(0x67, 0x00); + await this.writeRegister(0x70, 0x04); + await this.writeRegister(0x71, 0x01); + await this.writeRegister(0x72, 0xfe); + await this.writeRegister(0x76, 0x00); + await this.writeRegister(0x77, 0x00); + + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x0d, 0x01); + + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x80, 0x01); + await this.writeRegister(0x01, 0xf8); + + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x8e, 0x01); + await this.writeRegister(0x00, 0x01); + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x80, 0x00); + // end load tuning settings + + await this.writeRegister(0x0a, 0x04); + await this.writeRegister(0x84, (await this.readRegister(0x84)) & ~0x10); //active low + await this.writeRegister(0x0b, 0x01); + + let measurementTimingBudget = this.getMeasurementTimingBudget(); + + await this.writeRegister(0x01, 0xe8); + + //set measurement timing budget + + await this.writeRegister(0x01, 0x01); + if (!(await this.performCalibration(0x40))) return false; + + await this.writeRegister(0x01, 0x02); + if (!(await this.performCalibration(0x00))) return false; + + //Restore previous config + await this.writeRegister(0x01, 0xe8); + } + + private async performCalibration(input: number): Promise { + await this.writeRegister(0x00, 0x01 | input); + + await this.writeRegister(0x0b, 0x01); + await this.writeRegister(0x00, 0x00); + + return true; + } + + private async getMeasurementTimingBudget(): Promise { + let budget = 1910 + 960; + + let enables = await this.getSequenceStepEnables(); + let timeouts = await this.getSequenceStepTimeouts(enables); + + if (enables.tcc) { + budget += timeouts.msrc_dss_tcc_us + 590; + } + + if (enables.dss) { + budget += 2 * (timeouts.msrc_dss_tcc_us + 690); + } else if (enables.msrc) { + budget += timeouts.msrc_dss_tcc_us + 660; + } + + if (enables.pre_range) { + budget += timeouts.pre_range_us + 660; + } + + if (enables.final_range) { + budget += timeouts.final_range_us + 550; + } + + return budget; + } + + private async getSequenceStepTimeouts( + enables: SequenceStepEnables, + ): Promise { + let result = new SequenceStepTimeouts(); + result.pre_range_vcsel_period_pclks = this.decodeVcselPeriod( + await this.readRegister(0x50), + ); + + result.msrc_dss_tcc_mclks = await this.readRegister(0x46); + result.msrc_dss_tcc_us = this.timeoutMclksToMicroseconds( + result.msrc_dss_tcc_mclks, + result.pre_range_vcsel_period_pclks, + ); + + result.pre_range_mclks = this.decodeTimeout(await this.readShort(0x51)); + result.pre_range_us = this.timeoutMclksToMicroseconds( + result.pre_range_mclks, + result.pre_range_vcsel_period_pclks, + ); + + result.final_range_vcsel_period_pclks = this.decodeVcselPeriod( + await this.readRegister(0x70), + ); + + result.final_range_mclks = this.decodeTimeout(await this.readShort(0x71)); + + if (enables.pre_range) { + result.final_range_mclks -= result.pre_range_mclks; + } + + result.final_range_us = this.timeoutMclksToMicroseconds( + result.final_range_mclks, + result.final_range_vcsel_period_pclks, + ); + return result; + } + + private decodeTimeout(value: number): number { + return ((value & 0x00ff) << ((value & 0xff00) >> 8)) + 1; + } + + private decodeVcselPeriod(value: number) { + return (value + 1) << 1; + } + + private timeoutMclksToMicroseconds( + timeout_period_mclks: number, + vcsel_period_pclks: number, + ): number { + let macroPeriod = this.calcMacroPeriod(vcsel_period_pclks); + + return (timeout_period_mclks * macroPeriod + macroPeriod / 2) / 1000; + } + + private calcMacroPeriod(vcsel_period_pclks: number): number { + return (2304 * vcsel_period_pclks * 1655 + 500) / 1000; + } + + private async getSequenceStepEnables(): Promise { + let result = new SequenceStepEnables(); + + let sequenceConfig = await this.readRegister(0x01); + + result.tcc = ((sequenceConfig >> 4) & 0x01) != 0; + result.dss = ((sequenceConfig >> 3) & 0x01) != 0; + result.msrc = ((sequenceConfig >> 2) & 0x01) != 0; + result.pre_range = ((sequenceConfig >> 6) & 0x01) != 0; + result.final_range = ((sequenceConfig >> 7) & 0x01) != 0; + + return result; + } + + private async setSignalRateLimit(mcps: number): Promise { + await this.writeShort(0x44, mcps * (1 << 7)); + } + + // Get reference SPAD (single photon avalanche diode) count and type + // based on VL53L0X_get_info_from_device() + private async getSpadInfo() { + await this.writeRegister(0x80, 0x01); + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x00, 0x00); + await this.writeRegister(0xff, 0x06); + + await this.writeRegister(0x83, (await this.readRegister(0x83)) | 0x04); + await this.writeRegister(0xff, 0x07); + await this.writeRegister(0x81, 0x01); + + await this.writeRegister(0x80, 0x01); + + await this.writeRegister(0x94, 0x6b); + await this.writeRegister(0x83, 0x00); + + // reference has a timeout mechanism, but it doesn't seem to be necessary + + await this.writeRegister(0x83, 0x01); + let tmp = await this.readRegister(0x92); + + this.spadCount = tmp & 0x7f; + this.spadTypeIsAperture = ((tmp >> 7) & 0x01) == 0; + + await this.writeRegister(0x81, 0x00); + await this.writeRegister(0xff, 0x06); + await this.writeRegister(0x83, (await this.readRegister(0x83)) & ~0x04); + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x00, 0x01); + + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x80, 0x00); + } + + private async readRegister(register: number): Promise { + return readRegister(this.hub, this.channel, this.address, register); + } + + private async readMultipleBytes(register: number, n: number): Promise { + return readRegisterMultipleBytes( + this.hub, + this.channel, + this.address, + register, + n, + ); + } + + private async writeMultipleBytes(register: number, values: number[]): Promise { + return writeRegisterMultipleBytes( + this.hub, + this.channel, + this.address, + register, + values, + ); + } + + private async writeRegister(register: number, value: number) { + await writeRegister(this.hub, this.channel, this.address, register, value); + } + + private async writeShort(register: number, value: number) { + await writeShort(this.hub, this.channel, this.address, register, value); + } + + private async readShort(register: number): Promise { + return await readShort(this.hub, this.channel, this.address, register); + } +} + +class SequenceStepEnables { + tcc = false; + msrc = false; + dss = false; + pre_range = false; + final_range = false; +} + +class SequenceStepTimeouts { + pre_range_vcsel_period_pclks = 0; + final_range_vcsel_period_pclks = 0; + msrc_dss_tcc_mclks = 0; + pre_range_mclks = 0; + final_range_mclks = 0; + msrc_dss_tcc_us = 0; + pre_range_us = 0; + final_range_us = 0; +} diff --git a/packages/distance-sensor/src/i2c-utils.ts b/packages/distance-sensor/src/i2c-utils.ts new file mode 100644 index 00000000..157687be --- /dev/null +++ b/packages/distance-sensor/src/i2c-utils.ts @@ -0,0 +1,85 @@ +import { ExpansionHub } from "@rev-robotics/rev-hub-core"; + +export async function readRegister( + hub: ExpansionHub, + channel: number, + address: number, + register: number, +): Promise { + await hub.writeI2CSingleByte(channel, address, register); + await hub.readI2CSingleByte(channel, address); + + return (await hub.getI2CReadStatus(channel)).bytes[0]; +} + +export async function readRegisterMultipleBytes( + hub: ExpansionHub, + channel: number, + address: number, + register: number, + n: number, +): Promise { + await hub.writeI2CSingleByte(channel, address, register); + await hub.readI2CMultipleBytes(channel, address, n); + + return (await hub.getI2CReadStatus(channel)).bytes; +} + +export async function writeRegisterMultipleBytes( + hub: ExpansionHub, + channel: number, + address: number, + register: number, + values: number[], +): Promise { + await hub.writeI2CSingleByte(channel, address, register); + await hub.writeI2CMultipleBytes(channel, address, values); +} + +export async function writeRegister( + hub: ExpansionHub, + channel: number, + address: number, + register: number, + value: number, +) { + await hub.writeI2CMultipleBytes(channel, address, [register, value]); +} + +export async function writeShort( + hub: ExpansionHub, + channel: number, + address: number, + register: number, + value: number, +) { + await hub.writeI2CMultipleBytes(channel, address, [ + register, + ...shortToByteArray(value), + ]); +} + +export async function readShort( + hub: ExpansionHub, + channel: number, + address: number, + register: number, +) { + await hub.writeI2CSingleByte(channel, address, register); + + await hub.readI2CMultipleBytes(channel, address, 2); + + let bytes = (await hub.getI2CReadStatus(channel)).bytes; + + return (bytes[0] << 8) | bytes[1]; +} + +function shortToByteArray(value: number) { + // we want to represent the input as a 2-bytes array + const byteArray = [0, 0]; + + byteArray[0] = (value & 0xff00) >> 1; + byteArray[1] = value & 0xff; + + return byteArray; +} diff --git a/packages/distance-sensor/src/index.ts b/packages/distance-sensor/src/index.ts new file mode 100644 index 00000000..5d61a699 --- /dev/null +++ b/packages/distance-sensor/src/index.ts @@ -0,0 +1 @@ +export * from "./distance-sensor.js"; diff --git a/packages/distance-sensor/tsconfig.json b/packages/distance-sensor/tsconfig.json new file mode 100644 index 00000000..5c86a3d2 --- /dev/null +++ b/packages/distance-sensor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + } +} From 058da2d16e3eadedeefd408630554ecec90c4136 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 17 May 2023 16:42:40 -0500 Subject: [PATCH 078/148] Fix a few bugs in distance sensor setup --- .../distance-sensor/src/distance-sensor.ts | 120 +++++++++++++++++- packages/distance-sensor/src/i2c-utils.ts | 25 +++- 2 files changed, 138 insertions(+), 7 deletions(-) diff --git a/packages/distance-sensor/src/distance-sensor.ts b/packages/distance-sensor/src/distance-sensor.ts index 59e960ea..12a359c9 100644 --- a/packages/distance-sensor/src/distance-sensor.ts +++ b/packages/distance-sensor/src/distance-sensor.ts @@ -2,6 +2,7 @@ import { readRegister, readRegisterMultipleBytes, readShort, + writeInt, writeRegister, writeRegisterMultipleBytes, writeShort, @@ -19,6 +20,7 @@ export class DistanceSensor { private address: number = 0x52 / 2; private spadCount = 0; private spadTypeIsAperture = false; + private stopValue = 0; async is2mDistanceSensor(): Promise { if ((await this.readRegister(0xc0)) != 0xee) return false; @@ -28,13 +30,28 @@ export class DistanceSensor { else return true; } + async getDistanceMillimeters(): Promise { + try { + let range = await this.readShort(0x14 + 10); + await this.writeRegister(0x0b, 0x01); + + return range; + } catch (e) { + console.log("Got error:"); + console.log(e); + } + return -1; + } + async initialize() { + //set I2C standard mode await this.writeRegister(0x88, 0x00); + await this.writeRegister(0x80, 0x01); await this.writeRegister(0xff, 0x01); await this.writeRegister(0x00, 0x00); - let stopValue = await this.readRegister(0x91); + this.stopValue = await this.readRegister(0x91); await this.writeRegister(0x00, 0x01); await this.writeRegister(0xff, 0x00); @@ -68,11 +85,14 @@ export class DistanceSensor { } } - console.log(refSpadMap); + console.log(`Spads Enabled: ${spadsEnabled}`); + + console.log(refSpadMap.map((n) => n.toString(2).padStart(8, "0"))); - //begin load tuning settings await this.writeMultipleBytes(0xb0, refSpadMap); + //begin load tuning settings + await this.writeRegister(0xff, 0x01); await this.writeRegister(0x00, 0x00); @@ -172,11 +192,13 @@ export class DistanceSensor { await this.writeRegister(0x84, (await this.readRegister(0x84)) & ~0x10); //active low await this.writeRegister(0x0b, 0x01); - let measurementTimingBudget = this.getMeasurementTimingBudget(); + let measurementTimingBudget = await this.getMeasurementTimingBudget(); + console.log(`Timing budget: ${measurementTimingBudget}`); await this.writeRegister(0x01, 0xe8); //set measurement timing budget + await this.setMeasurementTimingBudget(measurementTimingBudget); await this.writeRegister(0x01, 0x01); if (!(await this.performCalibration(0x40))) return false; @@ -186,6 +208,28 @@ export class DistanceSensor { //Restore previous config await this.writeRegister(0x01, 0xe8); + + console.log("Starting continuous"); + await this.startContinuous(0); + } + + private async startContinuous(periodMs: number = 0) { + await this.writeRegister(0x80, 0x01); + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x00, 0x00); + await this.writeRegister(0x91, this.stopValue); + await this.writeRegister(0x00, 0x01); + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x80, 0x00); + + if (periodMs != 0) { + let calibrateValue = await this.readShort(0xf8); + if (calibrateValue != 0) { + periodMs *= calibrateValue; + } + + await this.writeInt(0x04, periodMs); + } } private async performCalibration(input: number): Promise { @@ -197,6 +241,50 @@ export class DistanceSensor { return true; } + private async setMeasurementTimingBudget(budget: number): Promise { + if (budget < 20000) return false; + + let usedBudget = 1320 + 960; + + let enables = await this.getSequenceStepEnables(); + let timeouts = await this.getSequenceStepTimeouts(enables); + + if (enables.tcc) { + usedBudget += timeouts.msrc_dss_tcc_us + 590; + } + + if (enables.dss) { + usedBudget += 2 * (timeouts.msrc_dss_tcc_us + 690); + } else if (enables.msrc) { + usedBudget += timeouts.msrc_dss_tcc_us + 660; + } + + if (enables.pre_range) { + usedBudget += timeouts.pre_range_us + 660; + } + + if (enables.final_range) { + usedBudget += 550; + + if (usedBudget > budget) return false; + + let finalTimeout = budget - usedBudget; + + let finalTimeoutMclks = this.timeoutMclksToMicroseconds( + finalTimeout, + timeouts.final_range_vcsel_period_pclks, + ); + + if (enables.pre_range) { + finalTimeoutMclks += timeouts.pre_range_mclks; + } + + await this.writeShort(0x71, this.encodeTimeout(finalTimeoutMclks)); + } + + return true; + } + private async getMeasurementTimingBudget(): Promise { let budget = 1910 + 960; @@ -261,6 +349,22 @@ export class DistanceSensor { return result; } + private encodeTimeout(mclks: number): number { + if (mclks > 0) { + let leastSignificantByte = mclks - 1; + let mostSignificantByte = 0; + + while ((leastSignificantByte & 0xffffff00) > 0) { + leastSignificantByte >>= 1; + mostSignificantByte++; + } + + return (mostSignificantByte << 8) | (leastSignificantByte & 0xff); + } else { + return 0; + } + } + private decodeTimeout(value: number): number { return ((value & 0x00ff) << ((value & 0xff00) >> 8)) + 1; } @@ -306,8 +410,8 @@ export class DistanceSensor { await this.writeRegister(0x80, 0x01); await this.writeRegister(0xff, 0x01); await this.writeRegister(0x00, 0x00); - await this.writeRegister(0xff, 0x06); + await this.writeRegister(0xff, 0x06); await this.writeRegister(0x83, (await this.readRegister(0x83)) | 0x04); await this.writeRegister(0xff, 0x07); await this.writeRegister(0x81, 0x01); @@ -323,7 +427,7 @@ export class DistanceSensor { let tmp = await this.readRegister(0x92); this.spadCount = tmp & 0x7f; - this.spadTypeIsAperture = ((tmp >> 7) & 0x01) == 0; + this.spadTypeIsAperture = ((tmp >> 7) & 0x01) != 0; await this.writeRegister(0x81, 0x00); await this.writeRegister(0xff, 0x06); @@ -370,6 +474,10 @@ export class DistanceSensor { private async readShort(register: number): Promise { return await readShort(this.hub, this.channel, this.address, register); } + + private async writeInt(register: number, value: number) { + await writeInt(this.hub, this.channel, this.address, register, value); + } } class SequenceStepEnables { diff --git a/packages/distance-sensor/src/i2c-utils.ts b/packages/distance-sensor/src/i2c-utils.ts index 157687be..6af14582 100644 --- a/packages/distance-sensor/src/i2c-utils.ts +++ b/packages/distance-sensor/src/i2c-utils.ts @@ -74,8 +74,20 @@ export async function readShort( return (bytes[0] << 8) | bytes[1]; } +export async function writeInt( + hub: ExpansionHub, + channel: number, + address: number, + register: number, + value: number, +) { + await hub.writeI2CMultipleBytes(channel, address, [ + register, + ...intToByteArray(value), + ]); +} + function shortToByteArray(value: number) { - // we want to represent the input as a 2-bytes array const byteArray = [0, 0]; byteArray[0] = (value & 0xff00) >> 1; @@ -83,3 +95,14 @@ function shortToByteArray(value: number) { return byteArray; } + +function intToByteArray(value: number): number[] { + const byteArray = [0, 0, 0, 0]; + + byteArray[0] = (value & 0xff000000) >> 24; + byteArray[1] = (value & 0xff0000) >> 16; + byteArray[2] = (value & 0xff00) >> 8; + byteArray[3] = value & 0xff; + + return byteArray; +} From 108925701c484914ad72342451850b3dd962a96c Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 18 May 2023 09:05:55 -0500 Subject: [PATCH 079/148] Fix errors in setup. Sensor now runs continuously, but values not correct yet. --- packages/distance-sensor/src/distance-sensor.ts | 10 ++++++---- packages/distance-sensor/src/i2c-utils.ts | 9 ++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/distance-sensor/src/distance-sensor.ts b/packages/distance-sensor/src/distance-sensor.ts index 12a359c9..f36e44fe 100644 --- a/packages/distance-sensor/src/distance-sensor.ts +++ b/packages/distance-sensor/src/distance-sensor.ts @@ -203,11 +203,10 @@ export class DistanceSensor { await this.writeRegister(0x01, 0x01); if (!(await this.performCalibration(0x40))) return false; + let config = await this.readRegister(0x01); await this.writeRegister(0x01, 0x02); - if (!(await this.performCalibration(0x00))) return false; - - //Restore previous config - await this.writeRegister(0x01, 0xe8); + await this.performCalibration(0x0); + await this.writeRegister(0x01, config); console.log("Starting continuous"); await this.startContinuous(0); @@ -229,6 +228,9 @@ export class DistanceSensor { } await this.writeInt(0x04, periodMs); + await this.writeRegister(0x00, 0x04); + } else { + await this.writeRegister(0x00, 0x02); } } diff --git a/packages/distance-sensor/src/i2c-utils.ts b/packages/distance-sensor/src/i2c-utils.ts index 6af14582..51405d33 100644 --- a/packages/distance-sensor/src/i2c-utils.ts +++ b/packages/distance-sensor/src/i2c-utils.ts @@ -32,8 +32,7 @@ export async function writeRegisterMultipleBytes( register: number, values: number[], ): Promise { - await hub.writeI2CSingleByte(channel, address, register); - await hub.writeI2CMultipleBytes(channel, address, values); + await hub.writeI2CMultipleBytes(channel, address, [register, ...values]); } export async function writeRegister( @@ -99,9 +98,9 @@ function shortToByteArray(value: number) { function intToByteArray(value: number): number[] { const byteArray = [0, 0, 0, 0]; - byteArray[0] = (value & 0xff000000) >> 24; - byteArray[1] = (value & 0xff0000) >> 16; - byteArray[2] = (value & 0xff00) >> 8; + byteArray[0] = (value >> 24) & 0xff; + byteArray[1] = (value >> 16) & 0xff; + byteArray[2] = (value >> 8) & 0xff; byteArray[3] = value & 0xff; return byteArray; From db8702635e781eb7fa6820d6ea44c2a1d1ca7a60 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 18 May 2023 10:35:11 -0500 Subject: [PATCH 080/148] separate code into methods --- .../distance-sensor/src/distance-sensor.ts | 541 ++---------------- packages/distance-sensor/src/registers.ts | 25 + 2 files changed, 79 insertions(+), 487 deletions(-) create mode 100644 packages/distance-sensor/src/registers.ts diff --git a/packages/distance-sensor/src/distance-sensor.ts b/packages/distance-sensor/src/distance-sensor.ts index f36e44fe..5a8b22ab 100644 --- a/packages/distance-sensor/src/distance-sensor.ts +++ b/packages/distance-sensor/src/distance-sensor.ts @@ -1,502 +1,69 @@ -import { - readRegister, - readRegisterMultipleBytes, - readShort, - writeInt, - writeRegister, - writeRegisterMultipleBytes, - writeShort, -} from "./i2c-utils.js"; -import { ExpansionHub } from "@rev-robotics/rev-hub-core"; +import { ExpansionHub } from "@rev-robotics/expansion-hub"; +import { VL53L0X } from "./drivers/vl53l0x.js"; +import { DistanceSensorDriver } from "./drivers/DistanceSensorDriver.js"; export class DistanceSensor { + /** + * + * @param hub the ExpansionHub or ControlHub that this sensor is physically + * connected to. + * @param channel the I2C channel this sensor is plugged into. + */ constructor(hub: ExpansionHub, channel: number) { - this.hub = hub; - this.channel = channel; + this.device = new VL53L0X(hub, channel); } - private readonly hub: ExpansionHub; - private readonly channel: number; - private address: number = 0x52 / 2; - private spadCount = 0; - private spadTypeIsAperture = false; - private stopValue = 0; + private readonly device: DistanceSensorDriver; + private timer?: NodeJS.Timer; + private isInitialized = false; - async is2mDistanceSensor(): Promise { - if ((await this.readRegister(0xc0)) != 0xee) return false; - if ((await this.readRegister(0xc1)) != 0xaa) return false; - if ((await this.readRegister(0xc2)) != 0x10) return false; - if ((await this.readRegister(0x61)) != 0x00) return false; - else return true; + /** + * Initializes the device + */ + async setup() { + await this.device.setup(); + this.isInitialized = true; } + /** + * Measure the current distance in millimeters. + */ async getDistanceMillimeters(): Promise { - try { - let range = await this.readShort(0x14 + 10); - await this.writeRegister(0x0b, 0x01); - - return range; - } catch (e) { - console.log("Got error:"); - console.log(e); - } - return -1; - } - - async initialize() { - //set I2C standard mode - await this.writeRegister(0x88, 0x00); - - await this.writeRegister(0x80, 0x01); - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x00, 0x00); - - this.stopValue = await this.readRegister(0x91); - - await this.writeRegister(0x00, 0x01); - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0x80, 0x00); - - let msgConfigControl = (await this.readRegister(0x60)) | 0x12; - await this.writeRegister(0x60, msgConfigControl); - - await this.setSignalRateLimit(0.25); - - await this.writeRegister(0x01, 0xff); - - await this.getSpadInfo(); - - let refSpadMap = await this.readMultipleBytes(0xb0, 6); - - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x4f, 0x00); - await this.writeRegister(0x4e, 0x2c); - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0xb6, 0xb4); - - let firstSpadToEnable = this.spadTypeIsAperture ? 12 : 0; - let spadsEnabled = 0; - - for (let i = 0; i < 48; i++) { - if (i < firstSpadToEnable || spadsEnabled == this.spadCount) { - refSpadMap[i / 8] &= ~(1 << i % 8); - } else if (((refSpadMap[i / 8] >> i % 8) & 0x01) != 0) { - spadsEnabled++; - } - } - - console.log(`Spads Enabled: ${spadsEnabled}`); - - console.log(refSpadMap.map((n) => n.toString(2).padStart(8, "0"))); - - await this.writeMultipleBytes(0xb0, refSpadMap); - - //begin load tuning settings - - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x00, 0x00); - - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0x09, 0x00); - await this.writeRegister(0x10, 0x00); - await this.writeRegister(0x11, 0x00); - - await this.writeRegister(0x24, 0x01); - await this.writeRegister(0x25, 0xff); - await this.writeRegister(0x75, 0x00); - - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x4e, 0x2c); - await this.writeRegister(0x48, 0x00); - await this.writeRegister(0x30, 0x20); - - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0x30, 0x09); - await this.writeRegister(0x54, 0x00); - await this.writeRegister(0x31, 0x04); - await this.writeRegister(0x32, 0x03); - await this.writeRegister(0x40, 0x83); - await this.writeRegister(0x46, 0x25); - await this.writeRegister(0x60, 0x00); - await this.writeRegister(0x27, 0x00); - await this.writeRegister(0x50, 0x06); - await this.writeRegister(0x51, 0x00); - await this.writeRegister(0x52, 0x96); - await this.writeRegister(0x56, 0x08); - await this.writeRegister(0x57, 0x30); - await this.writeRegister(0x61, 0x00); - await this.writeRegister(0x62, 0x00); - await this.writeRegister(0x64, 0x00); - await this.writeRegister(0x65, 0x00); - await this.writeRegister(0x66, 0xa0); - - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x22, 0x32); - await this.writeRegister(0x47, 0x14); - await this.writeRegister(0x49, 0xff); - await this.writeRegister(0x4a, 0x00); - - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0x7a, 0x0a); - await this.writeRegister(0x7b, 0x00); - await this.writeRegister(0x78, 0x21); - - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x23, 0x34); - await this.writeRegister(0x42, 0x00); - await this.writeRegister(0x44, 0xff); - await this.writeRegister(0x45, 0x26); - await this.writeRegister(0x46, 0x05); - await this.writeRegister(0x40, 0x40); - await this.writeRegister(0x0e, 0x06); - await this.writeRegister(0x20, 0x1a); - await this.writeRegister(0x43, 0x40); - - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0x34, 0x03); - await this.writeRegister(0x35, 0x44); - - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x31, 0x04); - await this.writeRegister(0x4b, 0x09); - await this.writeRegister(0x4c, 0x05); - await this.writeRegister(0x4d, 0x04); - - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0x44, 0x00); - await this.writeRegister(0x45, 0x20); - await this.writeRegister(0x47, 0x08); - await this.writeRegister(0x48, 0x28); - await this.writeRegister(0x67, 0x00); - await this.writeRegister(0x70, 0x04); - await this.writeRegister(0x71, 0x01); - await this.writeRegister(0x72, 0xfe); - await this.writeRegister(0x76, 0x00); - await this.writeRegister(0x77, 0x00); - - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x0d, 0x01); - - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0x80, 0x01); - await this.writeRegister(0x01, 0xf8); - - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x8e, 0x01); - await this.writeRegister(0x00, 0x01); - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0x80, 0x00); - // end load tuning settings - - await this.writeRegister(0x0a, 0x04); - await this.writeRegister(0x84, (await this.readRegister(0x84)) & ~0x10); //active low - await this.writeRegister(0x0b, 0x01); - - let measurementTimingBudget = await this.getMeasurementTimingBudget(); - console.log(`Timing budget: ${measurementTimingBudget}`); - - await this.writeRegister(0x01, 0xe8); - - //set measurement timing budget - await this.setMeasurementTimingBudget(measurementTimingBudget); - - await this.writeRegister(0x01, 0x01); - if (!(await this.performCalibration(0x40))) return false; - - let config = await this.readRegister(0x01); - await this.writeRegister(0x01, 0x02); - await this.performCalibration(0x0); - await this.writeRegister(0x01, config); - - console.log("Starting continuous"); - await this.startContinuous(0); - } - - private async startContinuous(periodMs: number = 0) { - await this.writeRegister(0x80, 0x01); - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x00, 0x00); - await this.writeRegister(0x91, this.stopValue); - await this.writeRegister(0x00, 0x01); - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0x80, 0x00); - - if (periodMs != 0) { - let calibrateValue = await this.readShort(0xf8); - if (calibrateValue != 0) { - periodMs *= calibrateValue; - } - - await this.writeInt(0x04, periodMs); - await this.writeRegister(0x00, 0x04); - } else { - await this.writeRegister(0x00, 0x02); - } - } - - private async performCalibration(input: number): Promise { - await this.writeRegister(0x00, 0x01 | input); - - await this.writeRegister(0x0b, 0x01); - await this.writeRegister(0x00, 0x00); - - return true; - } - - private async setMeasurementTimingBudget(budget: number): Promise { - if (budget < 20000) return false; - - let usedBudget = 1320 + 960; - - let enables = await this.getSequenceStepEnables(); - let timeouts = await this.getSequenceStepTimeouts(enables); - - if (enables.tcc) { - usedBudget += timeouts.msrc_dss_tcc_us + 590; - } - - if (enables.dss) { - usedBudget += 2 * (timeouts.msrc_dss_tcc_us + 690); - } else if (enables.msrc) { - usedBudget += timeouts.msrc_dss_tcc_us + 660; - } - - if (enables.pre_range) { - usedBudget += timeouts.pre_range_us + 660; - } - - if (enables.final_range) { - usedBudget += 550; - - if (usedBudget > budget) return false; - - let finalTimeout = budget - usedBudget; - - let finalTimeoutMclks = this.timeoutMclksToMicroseconds( - finalTimeout, - timeouts.final_range_vcsel_period_pclks, + if (!this.isInitialized) { + throw new Error( + "Distance Sensor is not initialized. Please call setup() first.", ); - - if (enables.pre_range) { - finalTimeoutMclks += timeouts.pre_range_mclks; - } - - await this.writeShort(0x71, this.encodeTimeout(finalTimeoutMclks)); - } - - return true; - } - - private async getMeasurementTimingBudget(): Promise { - let budget = 1910 + 960; - - let enables = await this.getSequenceStepEnables(); - let timeouts = await this.getSequenceStepTimeouts(enables); - - if (enables.tcc) { - budget += timeouts.msrc_dss_tcc_us + 590; } - - if (enables.dss) { - budget += 2 * (timeouts.msrc_dss_tcc_us + 690); - } else if (enables.msrc) { - budget += timeouts.msrc_dss_tcc_us + 660; - } - - if (enables.pre_range) { - budget += timeouts.pre_range_us + 660; - } - - if (enables.final_range) { - budget += timeouts.final_range_us + 550; - } - - return budget; - } - - private async getSequenceStepTimeouts( - enables: SequenceStepEnables, - ): Promise { - let result = new SequenceStepTimeouts(); - result.pre_range_vcsel_period_pclks = this.decodeVcselPeriod( - await this.readRegister(0x50), - ); - - result.msrc_dss_tcc_mclks = await this.readRegister(0x46); - result.msrc_dss_tcc_us = this.timeoutMclksToMicroseconds( - result.msrc_dss_tcc_mclks, - result.pre_range_vcsel_period_pclks, - ); - - result.pre_range_mclks = this.decodeTimeout(await this.readShort(0x51)); - result.pre_range_us = this.timeoutMclksToMicroseconds( - result.pre_range_mclks, - result.pre_range_vcsel_period_pclks, - ); - - result.final_range_vcsel_period_pclks = this.decodeVcselPeriod( - await this.readRegister(0x70), - ); - - result.final_range_mclks = this.decodeTimeout(await this.readShort(0x71)); - - if (enables.pre_range) { - result.final_range_mclks -= result.pre_range_mclks; + return await this.device.getDistanceMillimeters(); + } + + /** + * Begin recording distance continuously. + * @param onDistanceRecorded callback for when a distance is measured in mm. + * @param interval interval at which to start measurement. + */ + startMeasuringDistance( + onDistanceRecorded: (millimeters: number) => void, + interval: number, + ) { + if (!this.isInitialized) { + throw new Error( + "Distance Sensor is not initialized. Please call setup() first.", + ); } - - result.final_range_us = this.timeoutMclksToMicroseconds( - result.final_range_mclks, - result.final_range_vcsel_period_pclks, - ); - return result; - } - - private encodeTimeout(mclks: number): number { - if (mclks > 0) { - let leastSignificantByte = mclks - 1; - let mostSignificantByte = 0; - - while ((leastSignificantByte & 0xffffff00) > 0) { - leastSignificantByte >>= 1; - mostSignificantByte++; - } - - return (mostSignificantByte << 8) | (leastSignificantByte & 0xff); - } else { - return 0; + this.stop(); + this.timer = setInterval(async () => { + let distance = await this.getDistanceMillimeters(); + onDistanceRecorded(distance); + }, interval); + } + + /** + * Stops calling the measurement callback if one is defined. + */ + stop() { + if (this.timer) { + clearInterval(this.timer); } } - - private decodeTimeout(value: number): number { - return ((value & 0x00ff) << ((value & 0xff00) >> 8)) + 1; - } - - private decodeVcselPeriod(value: number) { - return (value + 1) << 1; - } - - private timeoutMclksToMicroseconds( - timeout_period_mclks: number, - vcsel_period_pclks: number, - ): number { - let macroPeriod = this.calcMacroPeriod(vcsel_period_pclks); - - return (timeout_period_mclks * macroPeriod + macroPeriod / 2) / 1000; - } - - private calcMacroPeriod(vcsel_period_pclks: number): number { - return (2304 * vcsel_period_pclks * 1655 + 500) / 1000; - } - - private async getSequenceStepEnables(): Promise { - let result = new SequenceStepEnables(); - - let sequenceConfig = await this.readRegister(0x01); - - result.tcc = ((sequenceConfig >> 4) & 0x01) != 0; - result.dss = ((sequenceConfig >> 3) & 0x01) != 0; - result.msrc = ((sequenceConfig >> 2) & 0x01) != 0; - result.pre_range = ((sequenceConfig >> 6) & 0x01) != 0; - result.final_range = ((sequenceConfig >> 7) & 0x01) != 0; - - return result; - } - - private async setSignalRateLimit(mcps: number): Promise { - await this.writeShort(0x44, mcps * (1 << 7)); - } - - // Get reference SPAD (single photon avalanche diode) count and type - // based on VL53L0X_get_info_from_device() - private async getSpadInfo() { - await this.writeRegister(0x80, 0x01); - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x00, 0x00); - - await this.writeRegister(0xff, 0x06); - await this.writeRegister(0x83, (await this.readRegister(0x83)) | 0x04); - await this.writeRegister(0xff, 0x07); - await this.writeRegister(0x81, 0x01); - - await this.writeRegister(0x80, 0x01); - - await this.writeRegister(0x94, 0x6b); - await this.writeRegister(0x83, 0x00); - - // reference has a timeout mechanism, but it doesn't seem to be necessary - - await this.writeRegister(0x83, 0x01); - let tmp = await this.readRegister(0x92); - - this.spadCount = tmp & 0x7f; - this.spadTypeIsAperture = ((tmp >> 7) & 0x01) != 0; - - await this.writeRegister(0x81, 0x00); - await this.writeRegister(0xff, 0x06); - await this.writeRegister(0x83, (await this.readRegister(0x83)) & ~0x04); - await this.writeRegister(0xff, 0x01); - await this.writeRegister(0x00, 0x01); - - await this.writeRegister(0xff, 0x00); - await this.writeRegister(0x80, 0x00); - } - - private async readRegister(register: number): Promise { - return readRegister(this.hub, this.channel, this.address, register); - } - - private async readMultipleBytes(register: number, n: number): Promise { - return readRegisterMultipleBytes( - this.hub, - this.channel, - this.address, - register, - n, - ); - } - - private async writeMultipleBytes(register: number, values: number[]): Promise { - return writeRegisterMultipleBytes( - this.hub, - this.channel, - this.address, - register, - values, - ); - } - - private async writeRegister(register: number, value: number) { - await writeRegister(this.hub, this.channel, this.address, register, value); - } - - private async writeShort(register: number, value: number) { - await writeShort(this.hub, this.channel, this.address, register, value); - } - - private async readShort(register: number): Promise { - return await readShort(this.hub, this.channel, this.address, register); - } - - private async writeInt(register: number, value: number) { - await writeInt(this.hub, this.channel, this.address, register, value); - } -} - -class SequenceStepEnables { - tcc = false; - msrc = false; - dss = false; - pre_range = false; - final_range = false; -} - -class SequenceStepTimeouts { - pre_range_vcsel_period_pclks = 0; - final_range_vcsel_period_pclks = 0; - msrc_dss_tcc_mclks = 0; - pre_range_mclks = 0; - final_range_mclks = 0; - msrc_dss_tcc_us = 0; - pre_range_us = 0; - final_range_us = 0; } diff --git a/packages/distance-sensor/src/registers.ts b/packages/distance-sensor/src/registers.ts new file mode 100644 index 00000000..9f87a6b0 --- /dev/null +++ b/packages/distance-sensor/src/registers.ts @@ -0,0 +1,25 @@ + +export const SYS_RANGE_START = 0x00; +export const SYSTEM_SEQUENCE_CONFIG = 0x01; +export const SYSTEM_INTERRUPT_CONFIG_GPIO = 0x0a; +export const SYSTEM_INTERRUPT_CLEAR = 0x0b; + +export const RESULT_RANGE_STATUS = 0x14; + +export const FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT = 0x44; +export const DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD = 0x4e; +export const DYNAMIC_SPAD_REF_EN_START_OFFSET = 0x4f; + +export const PRE_RANGE_CONFIG_VCSEL_PERIOD = 0x50; +export const FINAL_RANGE_CONFIG_VCSEL_PERIOD = 0x70; + +export const MSRC_CONFIG_TIMEOUT_MACROP = 0x46; +export const PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI = 0x51; +export const FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI = 0x71; + +export const MSRC_CONFIG_CONTROL = 0x60; + +export const GPIO_HV_MUX_ACTIVE_HIGH = 0x84; + +export const GLOBAL_CONFIG_SPAD_ENABLES_REF_0 = 0xb0; +export const GLOBAL_CONFIG_REF_EN_START_SELECT = 0xb6; From 22738b11b3328f6005c4994876f43376849ddfc7 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 18 May 2023 12:42:29 -0500 Subject: [PATCH 081/148] Get distance sensor working --- packages/distance-sensor/src/i2c-utils.ts | 17 ++++---- packages/distance-sensor/src/registers.ts | 1 + packages/sample/package.json | 20 +++++++++ packages/sample/src/main.ts | 52 +++++++++++++++++++++++ 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/packages/distance-sensor/src/i2c-utils.ts b/packages/distance-sensor/src/i2c-utils.ts index 51405d33..79ea052b 100644 --- a/packages/distance-sensor/src/i2c-utils.ts +++ b/packages/distance-sensor/src/i2c-utils.ts @@ -52,10 +52,13 @@ export async function writeShort( register: number, value: number, ) { - await hub.writeI2CMultipleBytes(channel, address, [ + await writeRegisterMultipleBytes( + hub, + channel, + address, register, - ...shortToByteArray(value), - ]); + shortToByteArray(value), + ); } export async function readShort( @@ -64,11 +67,7 @@ export async function readShort( address: number, register: number, ) { - await hub.writeI2CSingleByte(channel, address, register); - - await hub.readI2CMultipleBytes(channel, address, 2); - - let bytes = (await hub.getI2CReadStatus(channel)).bytes; + let bytes = await readRegisterMultipleBytes(hub, channel, address, register, 2); return (bytes[0] << 8) | bytes[1]; } @@ -89,7 +88,7 @@ export async function writeInt( function shortToByteArray(value: number) { const byteArray = [0, 0]; - byteArray[0] = (value & 0xff00) >> 1; + byteArray[0] = (value >> 8) & 0xff; byteArray[1] = value & 0xff; return byteArray; diff --git a/packages/distance-sensor/src/registers.ts b/packages/distance-sensor/src/registers.ts index 9f87a6b0..200ddf17 100644 --- a/packages/distance-sensor/src/registers.ts +++ b/packages/distance-sensor/src/registers.ts @@ -4,6 +4,7 @@ export const SYSTEM_SEQUENCE_CONFIG = 0x01; export const SYSTEM_INTERRUPT_CONFIG_GPIO = 0x0a; export const SYSTEM_INTERRUPT_CLEAR = 0x0b; +export const RESULT_INTERRUPT_STATUS = 0x13; export const RESULT_RANGE_STATUS = 0x14; export const FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT = 0x44; diff --git a/packages/sample/package.json b/packages/sample/package.json index b5541866..f7494e70 100644 --- a/packages/sample/package.json +++ b/packages/sample/package.json @@ -1,4 +1,5 @@ { +<<<<<<< HEAD "name": "rev-hub-cli", "descripton": "sample for testing Rev Hub code", "version": "1.0.0", @@ -33,3 +34,22 @@ "distance": "node dist/main.js distance 0" } } +======= + "name": "sample", + "descripton": "sample for testing Rev Hub code", + "version": "0.1.0", + "main": "dist/main.js", + "private": true, + "type": "module", + "dependencies": { + "@rev-robotics/expansion-hub": "*", + "@rev-robotics/distance-sensor": "*", + "commander": "^10.0.1" + }, + "scripts": { + "build": "tsc", + "distance": "node dist/main.js -d 0", + "list": "node dist/main.js -l" + } +} +>>>>>>> a8e1e4f (Get distance sensor working) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 26192cd3..1cde5649 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -40,6 +40,7 @@ program let digitalCommand = program.command("digital"); +<<<<<<< HEAD digitalCommand .command("write ") .description("write digital pin. Valid values for are high, low, 0, and 1.") @@ -52,6 +53,57 @@ digitalCommand stateBoolean = false; } else { program.error("Please provide only one of {high, low, 1, 0}"); +======= +if(options.list) { + console.log("Starting to search Serial Ports") + const hubs: ExpansionHub[] = await getConnectedExpansionHubs(); + hubs.forEach(async (hub) => { + hub.on("error", (e: any) => { + console.log(`Got error:`); + console.log(e); + }); + console.log(await toString(hub)); + }); +} + +if(options.distance) { + let channel = Number(options.distance) + console.log(`Channel number is ${channel}`); + + let hubs = await getConnectedExpansionHubs(); + let hub = hubs[0]; + + let sensor = new DistanceSensor(hub, channel); + + console.log("Checking sensor type"); + + if(!(await sensor.is2mDistanceSensor())) { + console.log("Sensor is not a valid distance sensor!"); + } + + console.log("Initializing sensor"); + + await sensor.initialize(); + + let timer = setInterval(async () => { + let distance = await sensor.getDistanceMillimeters(); + + console.log(`Distance is ${distance}mm`); + }, 1000); + + setTimeout(async () => { + clearInterval(timer); + hub.close(); + }, 10000); +} + +async function toString(hub: RevHub): Promise { + let result = `RevHub: ${hub.moduleAddress}\n`; + + if(hub.isParent()) { + for(const child of hub.getChildren()) { + result += `\tRevHub: ${child.moduleAddress}\n`; +>>>>>>> a8e1e4f (Get distance sensor working) } let digitalState = stateBoolean ? DigitalState.High : DigitalState.Low; From 31449cd50cb80d8b5d3d75418525ba2432df4075 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 18 May 2023 12:44:50 -0500 Subject: [PATCH 082/148] Increase duration of sample --- packages/sample/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 1cde5649..40df9439 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -94,7 +94,7 @@ if(options.distance) { setTimeout(async () => { clearInterval(timer); hub.close(); - }, 10000); + }, 20000); } async function toString(hub: RevHub): Promise { From 8fcb1c78db1cf16be1a94a22373b0f8c0aeadb5c Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 19 May 2023 09:42:22 -0500 Subject: [PATCH 083/148] Add note about close method --- packages/sample/package.json | 20 -------------- packages/sample/src/main.ts | 52 ------------------------------------ 2 files changed, 72 deletions(-) diff --git a/packages/sample/package.json b/packages/sample/package.json index f7494e70..b5541866 100644 --- a/packages/sample/package.json +++ b/packages/sample/package.json @@ -1,5 +1,4 @@ { -<<<<<<< HEAD "name": "rev-hub-cli", "descripton": "sample for testing Rev Hub code", "version": "1.0.0", @@ -34,22 +33,3 @@ "distance": "node dist/main.js distance 0" } } -======= - "name": "sample", - "descripton": "sample for testing Rev Hub code", - "version": "0.1.0", - "main": "dist/main.js", - "private": true, - "type": "module", - "dependencies": { - "@rev-robotics/expansion-hub": "*", - "@rev-robotics/distance-sensor": "*", - "commander": "^10.0.1" - }, - "scripts": { - "build": "tsc", - "distance": "node dist/main.js -d 0", - "list": "node dist/main.js -l" - } -} ->>>>>>> a8e1e4f (Get distance sensor working) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 40df9439..26192cd3 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -40,7 +40,6 @@ program let digitalCommand = program.command("digital"); -<<<<<<< HEAD digitalCommand .command("write ") .description("write digital pin. Valid values for are high, low, 0, and 1.") @@ -53,57 +52,6 @@ digitalCommand stateBoolean = false; } else { program.error("Please provide only one of {high, low, 1, 0}"); -======= -if(options.list) { - console.log("Starting to search Serial Ports") - const hubs: ExpansionHub[] = await getConnectedExpansionHubs(); - hubs.forEach(async (hub) => { - hub.on("error", (e: any) => { - console.log(`Got error:`); - console.log(e); - }); - console.log(await toString(hub)); - }); -} - -if(options.distance) { - let channel = Number(options.distance) - console.log(`Channel number is ${channel}`); - - let hubs = await getConnectedExpansionHubs(); - let hub = hubs[0]; - - let sensor = new DistanceSensor(hub, channel); - - console.log("Checking sensor type"); - - if(!(await sensor.is2mDistanceSensor())) { - console.log("Sensor is not a valid distance sensor!"); - } - - console.log("Initializing sensor"); - - await sensor.initialize(); - - let timer = setInterval(async () => { - let distance = await sensor.getDistanceMillimeters(); - - console.log(`Distance is ${distance}mm`); - }, 1000); - - setTimeout(async () => { - clearInterval(timer); - hub.close(); - }, 20000); -} - -async function toString(hub: RevHub): Promise { - let result = `RevHub: ${hub.moduleAddress}\n`; - - if(hub.isParent()) { - for(const child of hub.getChildren()) { - result += `\tRevHub: ${child.moduleAddress}\n`; ->>>>>>> a8e1e4f (Get distance sensor working) } let digitalState = stateBoolean ? DigitalState.High : DigitalState.Low; From 0f360474d10011515a17494109e9ded76eaf4bfb Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 19 May 2023 10:16:03 -0500 Subject: [PATCH 084/148] Abstract away the driver, providing a lighter-weight DistanceSensor class. --- .../distance-sensor/src/drivers/vl53l0x.ts | 522 ++++++++++++++++++ packages/sample/src/main.ts | 41 ++ 2 files changed, 563 insertions(+) create mode 100644 packages/distance-sensor/src/drivers/vl53l0x.ts diff --git a/packages/distance-sensor/src/drivers/vl53l0x.ts b/packages/distance-sensor/src/drivers/vl53l0x.ts new file mode 100644 index 00000000..58603cbf --- /dev/null +++ b/packages/distance-sensor/src/drivers/vl53l0x.ts @@ -0,0 +1,522 @@ +import { ExpansionHub } from "@rev-robotics/expansion-hub"; +import * as register from "../registers"; +import { SYSTEM_SEQUENCE_CONFIG } from "../registers"; +import { + readRegister, + readRegisterMultipleBytes, readShort, writeInt, + writeRegister, + writeRegisterMultipleBytes, + writeShort +} from "../i2c-utils"; + +export class VL53L0X { + constructor(hub: ExpansionHub, channel: number) { + this.hub = hub; + this.channel = channel; + } + + async setup(): Promise { + if(!await this.is2mDistanceSensor()) { + throw new Error(`I2C device on channel ${this.channel} is not a ` + + `valid 2m Distance sensor`); + } + + await this.initialize(); + } + + private readonly hub: ExpansionHub + private readonly channel: number + private address: number = 0x52/2; + private spadCount = 0; + private spadTypeIsAperture = false; + private stopValue = 0; + + /** + * This will zero out the sensor's stored stop variable for as long as + * it's powered on. This {@link DistanceSensor} will have cached the stop + * value as part of initialization, but no new {@link DistanceSensor} + * instances will be able to initialize until the physical sensor is power + * cycled. + */ + async close() { + await this.writeRegister(register.SYS_RANGE_START, 0x01); // VL53L0X_REG_SYSRANGE_MODE_SINGLESHOT + + await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0x00, 0x00); + await this.writeRegister(0x91, 0x00); + await this.writeRegister(0x00, 0x01); + await this.writeRegister(0xFF, 0x00); + } + + async is2mDistanceSensor(): Promise { + try { + if ((await this.readRegister(0xc0)) != 0xee) return false; + if ((await this.readRegister(0xc1)) != 0xaa) return false; + if ((await this.readRegister(0xc2)) != 0x10) return false; + if ((await this.readRegister(0x61)) != 0x00) return false; + else return true; + } catch { //if there's an I2C error, we don't have a working sensor. + return false; + } + } + + async getDistanceMillimeters(): Promise { + try { + let range = await this.readShort( + register.RESULT_RANGE_STATUS + 10); + await this.writeRegister( + register.SYSTEM_INTERRUPT_CLEAR, 0x01); + + return range; + } catch(e) { + console.log("Got error:"); + console.log(e); + } + return -1; + } + + async initData() { + await this.writeRegister(0x88, 0x00); + + await this.writeRegister(0x80, 0x01); + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x00, 0x00); + + this.stopValue = await this.readRegister(0x91); + + await this.writeRegister(0x00, 0x01); + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x80, 0x00); + } + + async loadTuningSettings() { + await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0x00, 0x00); + + await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0x09, 0x00); + await this.writeRegister(0x10, 0x00); + await this.writeRegister(0x11, 0x00); + + await this.writeRegister(0x24, 0x01); + await this.writeRegister(0x25, 0xFF); + await this.writeRegister(0x75, 0x00); + + await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0x4E, 0x2C); + await this.writeRegister(0x48, 0x00); + await this.writeRegister(0x30, 0x20); + + await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0x30, 0x09); + await this.writeRegister(0x54, 0x00); + await this.writeRegister(0x31, 0x04); + await this.writeRegister(0x32, 0x03); + await this.writeRegister(0x40, 0x83); + await this.writeRegister(0x46, 0x25); + await this.writeRegister(0x60, 0x00); + await this.writeRegister(0x27, 0x00); + await this.writeRegister(0x50, 0x06); + await this.writeRegister(0x51, 0x00); + await this.writeRegister(0x52, 0x96); + await this.writeRegister(0x56, 0x08); + await this.writeRegister(0x57, 0x30); + await this.writeRegister(0x61, 0x00); + await this.writeRegister(0x62, 0x00); + await this.writeRegister(0x64, 0x00); + await this.writeRegister(0x65, 0x00); + await this.writeRegister(0x66, 0xA0); + + await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0x22, 0x32); + await this.writeRegister(0x47, 0x14); + await this.writeRegister(0x49, 0xFF); + await this.writeRegister(0x4A, 0x00); + + await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0x7A, 0x0A); + await this.writeRegister(0x7B, 0x00); + await this.writeRegister(0x78, 0x21); + + await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0x23, 0x34); + await this.writeRegister(0x42, 0x00); + await this.writeRegister(0x44, 0xFF); + await this.writeRegister(0x45, 0x26); + await this.writeRegister(0x46, 0x05); + await this.writeRegister(0x40, 0x40); + await this.writeRegister(0x0E, 0x06); + await this.writeRegister(0x20, 0x1A); + await this.writeRegister(0x43, 0x40); + + await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0x34, 0x03); + await this.writeRegister(0x35, 0x44); + + await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0x31, 0x04); + await this.writeRegister(0x4B, 0x09); + await this.writeRegister(0x4C, 0x05); + await this.writeRegister(0x4D, 0x04); + + await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0x44, 0x00); + await this.writeRegister(0x45, 0x20); + await this.writeRegister(0x47, 0x08); + await this.writeRegister(0x48, 0x28); + await this.writeRegister(0x67, 0x00); + await this.writeRegister(0x70, 0x04); + await this.writeRegister(0x71, 0x01); + await this.writeRegister(0x72, 0xFE); + await this.writeRegister(0x76, 0x00); + await this.writeRegister(0x77, 0x00); + + await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0x0D, 0x01); + + await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0x80, 0x01); + await this.writeRegister(0x01, 0xF8); + + await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0x8E, 0x01); + await this.writeRegister(0x00, 0x01); + await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0x80, 0x00); + } + + private async initialize() { + //set I2C standard mode + await this.initData(); + + let msgConfigControl = (await this.readRegister(register.MSRC_CONFIG_CONTROL)) | 0x12; + await this.writeRegister(register.MSRC_CONFIG_CONTROL, msgConfigControl); + + await this.setSignalRateLimit(0.25); + + await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0xff); + + await this.getSpadInfo(); + + let refSpadMap = await this.readMultipleBytes(register.GLOBAL_CONFIG_SPAD_ENABLES_REF_0, 6); + + await this.writeRegister(0xff, 0x01); + await this.writeRegister(register.DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00); + await this.writeRegister(register.DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2c); + await this.writeRegister(0xff, 0x00); + await this.writeRegister(register.GLOBAL_CONFIG_REF_EN_START_SELECT, 0xb4); + + let firstSpadToEnable = (this.spadTypeIsAperture) ? 12 : 0; + let spadsEnabled = 0; + + for (let i = 0; i < 48; i++) { + let mapIndex = Math.floor(i / 8); + if (i < firstSpadToEnable || spadsEnabled == this.spadCount) { + refSpadMap[mapIndex] &= ~(1 << (i % 8)); //disable this spad. + } else if (((refSpadMap[mapIndex] >> (i % 8)) & 0x1) != 0) { + spadsEnabled++; + } + } + + await this.writeMultipleBytes(register.GLOBAL_CONFIG_SPAD_ENABLES_REF_0, refSpadMap); + + await this.loadTuningSettings(); + + await this.writeRegister(register.SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04); + await this.writeRegister(register.GPIO_HV_MUX_ACTIVE_HIGH, + (await this.readRegister(register.GPIO_HV_MUX_ACTIVE_HIGH)) & ~0x10); //active low + await this.writeRegister(register.SYSTEM_INTERRUPT_CLEAR, 0x01); + + //Commented this code out because the sensor doesn't correctly output + //if we set the timing measurement budget. + // let measurementTimingBudget = await this.getMeasurementTimingBudget(); + // console.log(`Timing budget: ${measurementTimingBudget}`); + + await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0xE8); + + //set measurement timing budget + // await this.setMeasurementTimingBudget(measurementTimingBudget); + + await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0x01); + if(!await this.performCalibration(0x40)) return false; + + await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0x02); + if(!await this.performCalibration(0x00)) return false; + + //Restore previous config + await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0xE8); + + await this.startContinuous(0); + } + + private async startContinuous(periodMs: number = 0) { + await this.writeRegister(0x80, 0x01); + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x00, 0x00); + await this.writeRegister(0x91, this.stopValue); + await this.writeRegister(0x00, 0x01); + await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0x80, 0x00); + + if(periodMs != 0) { + let calibrateValue = await this.readShort(0xf8); + if(calibrateValue != 0) { + periodMs *= calibrateValue; + } + + await this.writeInt(0x04, periodMs); + await this.writeRegister(register.SYS_RANGE_START, 0x04); + } else { + await this.writeRegister(register.SYS_RANGE_START, 0x02); + } + } + + private async performCalibration(input: number): Promise { + await this.writeRegister(register.SYS_RANGE_START, 0x01 | input); + + await this.writeRegister(0x0B, 0x01); + await this.writeRegister(register.SYS_RANGE_START, 0x00); + + return true; + } + + private async setMeasurementTimingBudget(budget: number): Promise { + if(budget < 20000) return false; + + let usedBudget = 1320 + 960; + + let enables = await this.getSequenceStepEnables(); + let timeouts = await this.getSequenceStepTimeouts(enables); + + if(enables.tcc) { + usedBudget += timeouts.msrc_dss_tcc_us + 590; + } + + if(enables.dss) { + usedBudget += 2 * (timeouts.msrc_dss_tcc_us + 690); + } else if(enables.msrc) { + usedBudget += timeouts.msrc_dss_tcc_us + 660; + } + + if(enables.pre_range) { + usedBudget += timeouts.pre_range_us + 660; + } + + if(enables.final_range) { + usedBudget += 550; + + if(usedBudget > budget) return false; + + let finalTimeout = budget - usedBudget; + + let finalTimeoutMclks = this.timeoutMclksToMicroseconds(finalTimeout, + timeouts.final_range_vcsel_period_pclks); + + if(enables.pre_range) { + finalTimeoutMclks += timeouts.pre_range_mclks; + } + + await this.writeShort(register.FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, + this.encodeTimeout(finalTimeoutMclks)); + } + + return true; + } + + private async getMeasurementTimingBudget(): Promise { + let budget = 1910 + 960; + + let enables = await this.getSequenceStepEnables(); + let timeouts = await this.getSequenceStepTimeouts(enables); + + if(enables.tcc) { + budget += timeouts.msrc_dss_tcc_us + 590; + } + + if(enables.dss) { + budget += 2*(timeouts.msrc_dss_tcc_us + 690); + } else if(enables.msrc) { + budget += timeouts.msrc_dss_tcc_us + 660; + } + + if(enables.pre_range) { + budget += timeouts.pre_range_us + 660; + } + + if(enables.final_range) { + budget += timeouts.final_range_us + 550; + } + + return budget; + } + + private async getSequenceStepTimeouts(enables: SequenceStepEnables): Promise { + let result = new SequenceStepTimeouts(); + result.pre_range_vcsel_period_pclks = this.decodeVcselPeriod( + await this.readRegister(register.PRE_RANGE_CONFIG_VCSEL_PERIOD)); + + result.msrc_dss_tcc_mclks = await this.readRegister(register.MSRC_CONFIG_TIMEOUT_MACROP) + 1; + result.msrc_dss_tcc_us = this.timeoutMclksToMicroseconds(result.msrc_dss_tcc_mclks, + result.pre_range_vcsel_period_pclks); + + result.pre_range_mclks = this.decodeTimeout(await this.readShort( + register.PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI)); + result.pre_range_us = this.timeoutMclksToMicroseconds(result.pre_range_mclks, + result.pre_range_vcsel_period_pclks); + + result.final_range_vcsel_period_pclks = this.decodeVcselPeriod( + await this.readRegister(register.FINAL_RANGE_CONFIG_VCSEL_PERIOD)); + + result.final_range_mclks = this.decodeTimeout(await this.readShort( + register.FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI)); + + if(enables.pre_range) { + result.final_range_mclks -= result.pre_range_mclks; + } + + result.final_range_us = this.timeoutMclksToMicroseconds(result.final_range_mclks, + result.final_range_vcsel_period_pclks); + return result; + } + + private encodeTimeout(mclks: number): number { + if(mclks> 0) { + let leastSignificantByte = mclks-1; + let mostSignificantByte = 0; + + while((leastSignificantByte & 0xFFFFFF00) > 0) { + leastSignificantByte >>= 1; + mostSignificantByte++; + } + + return (mostSignificantByte << 8) | (leastSignificantByte & 0xFF); + } else { + return 0; + } + } + + private decodeTimeout(value: number): number { + return ((value & 0x00FF) << ((value & 0xFF00) >> 8)) + 1; + } + + private decodeVcselPeriod(value: number) { + return (value + 1) << 1; + } + + private timeoutMclksToMicroseconds(timeout_period_mclks: number, vcsel_period_pclks: number): number { + let macroPeriod = this.calcMacroPeriod(vcsel_period_pclks); + + return ((timeout_period_mclks * macroPeriod) + (macroPeriod / 2)) / 1000 + } + + private calcMacroPeriod(vcsel_period_pclks: number): number { + return (((2304 * (vcsel_period_pclks) * 1655) + 500) / 1000); + } + + private async getSequenceStepEnables(): Promise { + let result = new SequenceStepEnables(); + + let sequenceConfig = await this.readRegister(SYSTEM_SEQUENCE_CONFIG); + + result.tcc = ((sequenceConfig >> 4) & 0x1) != 0; + result.dss = ((sequenceConfig >> 3) & 0x1) != 0; + result.msrc = ((sequenceConfig >> 2) & 0x1) != 0; + result.pre_range = ((sequenceConfig >> 6) & 0x1) != 0; + result.final_range = ((sequenceConfig >> 7) & 0x1) != 0; + + return result; + } + + private async setSignalRateLimit(mcps: number): Promise { + await this.writeShort(register.FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, (mcps * (1<<7))); + } + + private async getSignalRateLimit(): Promise { + return (await this.readShort(register.FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT)) / (1 << 7); + } + + // Get reference SPAD (single photon avalanche diode) count and type + // based on VL53L0X_get_info_from_device() + private async getSpadInfo() { + await this.writeRegister(0x80, 0x01); + await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0x00, 0x00); + + await this.writeRegister(0xFF, 0x06); + await this.writeRegister(0x83, await this.readRegister(0x83) | 0x04); + await this.writeRegister(0xFF, 0x07); + await this.writeRegister(0x81, 0x01); + + await this.writeRegister(0x80, 0x01); + + await this.writeRegister(0x94, 0x6b); + await this.writeRegister(0x83, 0x00); + + //wait for the device to be ready + while(await this.readRegister(0x83) == 0); + + await this.writeRegister(0x83, 0x01); + let tmp = await this.readRegister(0x92); + + this.spadCount = tmp & 0x7f; + this.spadTypeIsAperture = ((tmp >> 7) & 0x01) != 0; + + await this.writeRegister(0x81, 0x00); + await this.writeRegister(0xff, 0x06); + let value = await this.readRegister(0x83); + await this.writeRegister(0x83, value & 0xfb); + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x00, 0x01); + + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x80, 0x00); + } + + private async readRegister(register: number): Promise { + return await readRegister(this.hub, this.channel, this.address, register); + } + + private async readMultipleBytes(register: number, n: number): Promise { + return await readRegisterMultipleBytes(this.hub, this.channel, this.address, register, n); + } + + private async writeMultipleBytes(register: number, values: number[]): Promise { + return await writeRegisterMultipleBytes(this.hub, this.channel, this.address, register, values); + } + + private async writeRegister(register: number, value: number) { + await writeRegister(this.hub, this.channel, this.address, register, value); + } + + private async writeShort(register: number, value: number) { + await writeShort(this.hub, this.channel, this.address, register, value); + } + + private async readShort(register: number): Promise { + return await readShort(this.hub, this.channel, this.address, register); + } + + private async writeInt(register: number, value: number) { + await writeInt(this.hub, this.channel, this.address, register, value); + } +} + +class SequenceStepEnables { + tcc = false; + msrc = false; + dss = false; + pre_range = false; + final_range = false; +} + +class SequenceStepTimeouts { + pre_range_vcsel_period_pclks = 0; + final_range_vcsel_period_pclks = 0; + msrc_dss_tcc_mclks = 0; + pre_range_mclks = 0; + final_range_mclks = 0; + msrc_dss_tcc_us = 0; + pre_range_us = 0; + final_range_us = 0; +} + diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 26192cd3..5e43ab63 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -40,6 +40,7 @@ program let digitalCommand = program.command("digital"); +<<<<<<< HEAD digitalCommand .command("write ") .description("write digital pin. Valid values for are high, low, 0, and 1.") @@ -52,6 +53,46 @@ digitalCommand stateBoolean = false; } else { program.error("Please provide only one of {high, low, 1, 0}"); +======= +if(options.list) { + console.log("Starting to search Serial Ports") + const hubs: ExpansionHub[] = await getConnectedExpansionHubs(); + hubs.forEach(async (hub) => { + hub.on("error", (e: any) => { + console.log(`Got error:`); + console.log(e); + }); + console.log(await toString(hub)); + }); +} + +if(options.distance) { + let channel = Number(options.distance) + console.log(`Channel number is ${channel}`); + + let hubs = await getConnectedExpansionHubs(); + let hub = hubs[0]; + + let sensor = new DistanceSensor(hub, channel); + await sensor.setup(); + + sensor.startMeasuringDistance((distance) => { + console.log(`Distance is ${distance}mm`); + }, 1000); + + setTimeout(async () => { + sensor.stop(); + hub.close(); + }, 20000); +} + +async function toString(hub: RevHub): Promise { + let result = `RevHub: ${hub.moduleAddress}\n`; + + if(hub.isParent()) { + for(const child of hub.getChildren()) { + result += `\tRevHub: ${child.moduleAddress}\n`; +>>>>>>> fb77285 (Abstract away the driver, providing a lighter-weight DistanceSensor class.) } let digitalState = stateBoolean ? DigitalState.High : DigitalState.Low; From 09f27db36b28edabdf630f5d15984b456370dddd Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 19 May 2023 10:29:20 -0500 Subject: [PATCH 085/148] Create interface for distance sensor --- .../distance-sensor/src/distance-sensor.ts | 2 +- .../src/drivers/DistanceSensorDriver.ts | 4 + .../distance-sensor/src/drivers/vl53l0x.ts | 293 ++++++++++-------- 3 files changed, 176 insertions(+), 123 deletions(-) create mode 100644 packages/distance-sensor/src/drivers/DistanceSensorDriver.ts diff --git a/packages/distance-sensor/src/distance-sensor.ts b/packages/distance-sensor/src/distance-sensor.ts index 5a8b22ab..23b22424 100644 --- a/packages/distance-sensor/src/distance-sensor.ts +++ b/packages/distance-sensor/src/distance-sensor.ts @@ -1,6 +1,6 @@ -import { ExpansionHub } from "@rev-robotics/expansion-hub"; import { VL53L0X } from "./drivers/vl53l0x.js"; import { DistanceSensorDriver } from "./drivers/DistanceSensorDriver.js"; +import { ExpansionHub } from "@rev-robotics/rev-hub-core"; export class DistanceSensor { /** diff --git a/packages/distance-sensor/src/drivers/DistanceSensorDriver.ts b/packages/distance-sensor/src/drivers/DistanceSensorDriver.ts new file mode 100644 index 00000000..6e19f0e3 --- /dev/null +++ b/packages/distance-sensor/src/drivers/DistanceSensorDriver.ts @@ -0,0 +1,4 @@ +export interface DistanceSensorDriver { + getDistanceMillimeters(): Promise; + setup(): Promise; +} diff --git a/packages/distance-sensor/src/drivers/vl53l0x.ts b/packages/distance-sensor/src/drivers/vl53l0x.ts index 58603cbf..69864627 100644 --- a/packages/distance-sensor/src/drivers/vl53l0x.ts +++ b/packages/distance-sensor/src/drivers/vl53l0x.ts @@ -1,32 +1,36 @@ -import { ExpansionHub } from "@rev-robotics/expansion-hub"; -import * as register from "../registers"; -import { SYSTEM_SEQUENCE_CONFIG } from "../registers"; +import * as register from "../registers.js"; import { readRegister, - readRegisterMultipleBytes, readShort, writeInt, + readRegisterMultipleBytes, + readShort, + writeInt, writeRegister, writeRegisterMultipleBytes, - writeShort -} from "../i2c-utils"; + writeShort, +} from "../i2c-utils.js"; +import { DistanceSensorDriver } from "./DistanceSensorDriver.js"; +import { ExpansionHub } from "@rev-robotics/rev-hub-core"; -export class VL53L0X { +export class VL53L0X implements DistanceSensorDriver { constructor(hub: ExpansionHub, channel: number) { this.hub = hub; this.channel = channel; } async setup(): Promise { - if(!await this.is2mDistanceSensor()) { - throw new Error(`I2C device on channel ${this.channel} is not a ` + - `valid 2m Distance sensor`); + if (!(await this.is2mDistanceSensor())) { + throw new Error( + `I2C device on channel ${this.channel} is not a ` + + `valid 2m Distance sensor`, + ); } await this.initialize(); } - private readonly hub: ExpansionHub - private readonly channel: number - private address: number = 0x52/2; + private readonly hub: ExpansionHub; + private readonly channel: number; + private address: number = 0x52 / 2; private spadCount = 0; private spadTypeIsAperture = false; private stopValue = 0; @@ -41,11 +45,11 @@ export class VL53L0X { async close() { await this.writeRegister(register.SYS_RANGE_START, 0x01); // VL53L0X_REG_SYSRANGE_MODE_SINGLESHOT - await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0xff, 0x01); await this.writeRegister(0x00, 0x00); await this.writeRegister(0x91, 0x00); await this.writeRegister(0x00, 0x01); - await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0xff, 0x00); } async is2mDistanceSensor(): Promise { @@ -55,20 +59,19 @@ export class VL53L0X { if ((await this.readRegister(0xc2)) != 0x10) return false; if ((await this.readRegister(0x61)) != 0x00) return false; else return true; - } catch { //if there's an I2C error, we don't have a working sensor. + } catch { + //if there's an I2C error, we don't have a working sensor. return false; } } async getDistanceMillimeters(): Promise { try { - let range = await this.readShort( - register.RESULT_RANGE_STATUS + 10); - await this.writeRegister( - register.SYSTEM_INTERRUPT_CLEAR, 0x01); + let range = await this.readShort(register.RESULT_RANGE_STATUS + 10); + await this.writeRegister(register.SYSTEM_INTERRUPT_CLEAR, 0x01); return range; - } catch(e) { + } catch (e) { console.log("Got error:"); console.log(e); } @@ -90,24 +93,24 @@ export class VL53L0X { } async loadTuningSettings() { - await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0xff, 0x01); await this.writeRegister(0x00, 0x00); - await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0xff, 0x00); await this.writeRegister(0x09, 0x00); await this.writeRegister(0x10, 0x00); await this.writeRegister(0x11, 0x00); await this.writeRegister(0x24, 0x01); - await this.writeRegister(0x25, 0xFF); + await this.writeRegister(0x25, 0xff); await this.writeRegister(0x75, 0x00); - await this.writeRegister(0xFF, 0x01); - await this.writeRegister(0x4E, 0x2C); + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x4e, 0x2c); await this.writeRegister(0x48, 0x00); await this.writeRegister(0x30, 0x20); - await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0xff, 0x00); await this.writeRegister(0x30, 0x09); await this.writeRegister(0x54, 0x00); await this.writeRegister(0x31, 0x04); @@ -125,41 +128,41 @@ export class VL53L0X { await this.writeRegister(0x62, 0x00); await this.writeRegister(0x64, 0x00); await this.writeRegister(0x65, 0x00); - await this.writeRegister(0x66, 0xA0); + await this.writeRegister(0x66, 0xa0); - await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0xff, 0x01); await this.writeRegister(0x22, 0x32); await this.writeRegister(0x47, 0x14); - await this.writeRegister(0x49, 0xFF); - await this.writeRegister(0x4A, 0x00); + await this.writeRegister(0x49, 0xff); + await this.writeRegister(0x4a, 0x00); - await this.writeRegister(0xFF, 0x00); - await this.writeRegister(0x7A, 0x0A); - await this.writeRegister(0x7B, 0x00); + await this.writeRegister(0xff, 0x00); + await this.writeRegister(0x7a, 0x0a); + await this.writeRegister(0x7b, 0x00); await this.writeRegister(0x78, 0x21); - await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0xff, 0x01); await this.writeRegister(0x23, 0x34); await this.writeRegister(0x42, 0x00); - await this.writeRegister(0x44, 0xFF); + await this.writeRegister(0x44, 0xff); await this.writeRegister(0x45, 0x26); await this.writeRegister(0x46, 0x05); await this.writeRegister(0x40, 0x40); - await this.writeRegister(0x0E, 0x06); - await this.writeRegister(0x20, 0x1A); + await this.writeRegister(0x0e, 0x06); + await this.writeRegister(0x20, 0x1a); await this.writeRegister(0x43, 0x40); - await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0xff, 0x00); await this.writeRegister(0x34, 0x03); await this.writeRegister(0x35, 0x44); - await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0xff, 0x01); await this.writeRegister(0x31, 0x04); - await this.writeRegister(0x4B, 0x09); - await this.writeRegister(0x4C, 0x05); - await this.writeRegister(0x4D, 0x04); + await this.writeRegister(0x4b, 0x09); + await this.writeRegister(0x4c, 0x05); + await this.writeRegister(0x4d, 0x04); - await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0xff, 0x00); await this.writeRegister(0x44, 0x00); await this.writeRegister(0x45, 0x20); await this.writeRegister(0x47, 0x08); @@ -167,21 +170,21 @@ export class VL53L0X { await this.writeRegister(0x67, 0x00); await this.writeRegister(0x70, 0x04); await this.writeRegister(0x71, 0x01); - await this.writeRegister(0x72, 0xFE); + await this.writeRegister(0x72, 0xfe); await this.writeRegister(0x76, 0x00); await this.writeRegister(0x77, 0x00); - await this.writeRegister(0xFF, 0x01); - await this.writeRegister(0x0D, 0x01); + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x0d, 0x01); - await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0xff, 0x00); await this.writeRegister(0x80, 0x01); - await this.writeRegister(0x01, 0xF8); + await this.writeRegister(0x01, 0xf8); - await this.writeRegister(0xFF, 0x01); - await this.writeRegister(0x8E, 0x01); + await this.writeRegister(0xff, 0x01); + await this.writeRegister(0x8e, 0x01); await this.writeRegister(0x00, 0x01); - await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0xff, 0x00); await this.writeRegister(0x80, 0x00); } @@ -189,7 +192,8 @@ export class VL53L0X { //set I2C standard mode await this.initData(); - let msgConfigControl = (await this.readRegister(register.MSRC_CONFIG_CONTROL)) | 0x12; + let msgConfigControl = + (await this.readRegister(register.MSRC_CONFIG_CONTROL)) | 0x12; await this.writeRegister(register.MSRC_CONFIG_CONTROL, msgConfigControl); await this.setSignalRateLimit(0.25); @@ -198,7 +202,10 @@ export class VL53L0X { await this.getSpadInfo(); - let refSpadMap = await this.readMultipleBytes(register.GLOBAL_CONFIG_SPAD_ENABLES_REF_0, 6); + let refSpadMap = await this.readMultipleBytes( + register.GLOBAL_CONFIG_SPAD_ENABLES_REF_0, + 6, + ); await this.writeRegister(0xff, 0x01); await this.writeRegister(register.DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00); @@ -206,25 +213,30 @@ export class VL53L0X { await this.writeRegister(0xff, 0x00); await this.writeRegister(register.GLOBAL_CONFIG_REF_EN_START_SELECT, 0xb4); - let firstSpadToEnable = (this.spadTypeIsAperture) ? 12 : 0; + let firstSpadToEnable = this.spadTypeIsAperture ? 12 : 0; let spadsEnabled = 0; for (let i = 0; i < 48; i++) { let mapIndex = Math.floor(i / 8); if (i < firstSpadToEnable || spadsEnabled == this.spadCount) { - refSpadMap[mapIndex] &= ~(1 << (i % 8)); //disable this spad. - } else if (((refSpadMap[mapIndex] >> (i % 8)) & 0x1) != 0) { + refSpadMap[mapIndex] &= ~(1 << i % 8); //disable this spad. + } else if (((refSpadMap[mapIndex] >> i % 8) & 0x1) != 0) { spadsEnabled++; } } - await this.writeMultipleBytes(register.GLOBAL_CONFIG_SPAD_ENABLES_REF_0, refSpadMap); + await this.writeMultipleBytes( + register.GLOBAL_CONFIG_SPAD_ENABLES_REF_0, + refSpadMap, + ); await this.loadTuningSettings(); await this.writeRegister(register.SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04); - await this.writeRegister(register.GPIO_HV_MUX_ACTIVE_HIGH, - (await this.readRegister(register.GPIO_HV_MUX_ACTIVE_HIGH)) & ~0x10); //active low + await this.writeRegister( + register.GPIO_HV_MUX_ACTIVE_HIGH, + (await this.readRegister(register.GPIO_HV_MUX_ACTIVE_HIGH)) & ~0x10, + ); //active low await this.writeRegister(register.SYSTEM_INTERRUPT_CLEAR, 0x01); //Commented this code out because the sensor doesn't correctly output @@ -232,19 +244,19 @@ export class VL53L0X { // let measurementTimingBudget = await this.getMeasurementTimingBudget(); // console.log(`Timing budget: ${measurementTimingBudget}`); - await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0xE8); + await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0xe8); //set measurement timing budget // await this.setMeasurementTimingBudget(measurementTimingBudget); await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0x01); - if(!await this.performCalibration(0x40)) return false; + if (!(await this.performCalibration(0x40))) return false; await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0x02); - if(!await this.performCalibration(0x00)) return false; + if (!(await this.performCalibration(0x00))) return false; //Restore previous config - await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0xE8); + await this.writeRegister(register.SYSTEM_SEQUENCE_CONFIG, 0xe8); await this.startContinuous(0); } @@ -255,12 +267,12 @@ export class VL53L0X { await this.writeRegister(0x00, 0x00); await this.writeRegister(0x91, this.stopValue); await this.writeRegister(0x00, 0x01); - await this.writeRegister(0xFF, 0x00); + await this.writeRegister(0xff, 0x00); await this.writeRegister(0x80, 0x00); - if(periodMs != 0) { + if (periodMs != 0) { let calibrateValue = await this.readShort(0xf8); - if(calibrateValue != 0) { + if (calibrateValue != 0) { periodMs *= calibrateValue; } @@ -274,50 +286,54 @@ export class VL53L0X { private async performCalibration(input: number): Promise { await this.writeRegister(register.SYS_RANGE_START, 0x01 | input); - await this.writeRegister(0x0B, 0x01); + await this.writeRegister(0x0b, 0x01); await this.writeRegister(register.SYS_RANGE_START, 0x00); return true; } private async setMeasurementTimingBudget(budget: number): Promise { - if(budget < 20000) return false; + if (budget < 20000) return false; let usedBudget = 1320 + 960; let enables = await this.getSequenceStepEnables(); let timeouts = await this.getSequenceStepTimeouts(enables); - if(enables.tcc) { + if (enables.tcc) { usedBudget += timeouts.msrc_dss_tcc_us + 590; } - if(enables.dss) { + if (enables.dss) { usedBudget += 2 * (timeouts.msrc_dss_tcc_us + 690); - } else if(enables.msrc) { + } else if (enables.msrc) { usedBudget += timeouts.msrc_dss_tcc_us + 660; } - if(enables.pre_range) { + if (enables.pre_range) { usedBudget += timeouts.pre_range_us + 660; } - if(enables.final_range) { + if (enables.final_range) { usedBudget += 550; - if(usedBudget > budget) return false; + if (usedBudget > budget) return false; let finalTimeout = budget - usedBudget; - let finalTimeoutMclks = this.timeoutMclksToMicroseconds(finalTimeout, - timeouts.final_range_vcsel_period_pclks); + let finalTimeoutMclks = this.timeoutMclksToMicroseconds( + finalTimeout, + timeouts.final_range_vcsel_period_pclks, + ); - if(enables.pre_range) { + if (enables.pre_range) { finalTimeoutMclks += timeouts.pre_range_mclks; } - await this.writeShort(register.FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, - this.encodeTimeout(finalTimeoutMclks)); + await this.writeShort( + register.FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, + this.encodeTimeout(finalTimeoutMclks), + ); } return true; @@ -329,94 +345,110 @@ export class VL53L0X { let enables = await this.getSequenceStepEnables(); let timeouts = await this.getSequenceStepTimeouts(enables); - if(enables.tcc) { + if (enables.tcc) { budget += timeouts.msrc_dss_tcc_us + 590; } - if(enables.dss) { - budget += 2*(timeouts.msrc_dss_tcc_us + 690); - } else if(enables.msrc) { + if (enables.dss) { + budget += 2 * (timeouts.msrc_dss_tcc_us + 690); + } else if (enables.msrc) { budget += timeouts.msrc_dss_tcc_us + 660; } - if(enables.pre_range) { + if (enables.pre_range) { budget += timeouts.pre_range_us + 660; } - if(enables.final_range) { + if (enables.final_range) { budget += timeouts.final_range_us + 550; } return budget; } - private async getSequenceStepTimeouts(enables: SequenceStepEnables): Promise { + private async getSequenceStepTimeouts( + enables: SequenceStepEnables, + ): Promise { let result = new SequenceStepTimeouts(); result.pre_range_vcsel_period_pclks = this.decodeVcselPeriod( - await this.readRegister(register.PRE_RANGE_CONFIG_VCSEL_PERIOD)); - - result.msrc_dss_tcc_mclks = await this.readRegister(register.MSRC_CONFIG_TIMEOUT_MACROP) + 1; - result.msrc_dss_tcc_us = this.timeoutMclksToMicroseconds(result.msrc_dss_tcc_mclks, - result.pre_range_vcsel_period_pclks); - - result.pre_range_mclks = this.decodeTimeout(await this.readShort( - register.PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI)); - result.pre_range_us = this.timeoutMclksToMicroseconds(result.pre_range_mclks, - result.pre_range_vcsel_period_pclks); + await this.readRegister(register.PRE_RANGE_CONFIG_VCSEL_PERIOD), + ); + + result.msrc_dss_tcc_mclks = + (await this.readRegister(register.MSRC_CONFIG_TIMEOUT_MACROP)) + 1; + result.msrc_dss_tcc_us = this.timeoutMclksToMicroseconds( + result.msrc_dss_tcc_mclks, + result.pre_range_vcsel_period_pclks, + ); + + result.pre_range_mclks = this.decodeTimeout( + await this.readShort(register.PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI), + ); + result.pre_range_us = this.timeoutMclksToMicroseconds( + result.pre_range_mclks, + result.pre_range_vcsel_period_pclks, + ); result.final_range_vcsel_period_pclks = this.decodeVcselPeriod( - await this.readRegister(register.FINAL_RANGE_CONFIG_VCSEL_PERIOD)); + await this.readRegister(register.FINAL_RANGE_CONFIG_VCSEL_PERIOD), + ); - result.final_range_mclks = this.decodeTimeout(await this.readShort( - register.FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI)); + result.final_range_mclks = this.decodeTimeout( + await this.readShort(register.FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI), + ); - if(enables.pre_range) { + if (enables.pre_range) { result.final_range_mclks -= result.pre_range_mclks; } - result.final_range_us = this.timeoutMclksToMicroseconds(result.final_range_mclks, - result.final_range_vcsel_period_pclks); + result.final_range_us = this.timeoutMclksToMicroseconds( + result.final_range_mclks, + result.final_range_vcsel_period_pclks, + ); return result; } private encodeTimeout(mclks: number): number { - if(mclks> 0) { - let leastSignificantByte = mclks-1; + if (mclks > 0) { + let leastSignificantByte = mclks - 1; let mostSignificantByte = 0; - while((leastSignificantByte & 0xFFFFFF00) > 0) { + while ((leastSignificantByte & 0xffffff00) > 0) { leastSignificantByte >>= 1; mostSignificantByte++; } - return (mostSignificantByte << 8) | (leastSignificantByte & 0xFF); + return (mostSignificantByte << 8) | (leastSignificantByte & 0xff); } else { return 0; } } private decodeTimeout(value: number): number { - return ((value & 0x00FF) << ((value & 0xFF00) >> 8)) + 1; + return ((value & 0x00ff) << ((value & 0xff00) >> 8)) + 1; } private decodeVcselPeriod(value: number) { return (value + 1) << 1; } - private timeoutMclksToMicroseconds(timeout_period_mclks: number, vcsel_period_pclks: number): number { + private timeoutMclksToMicroseconds( + timeout_period_mclks: number, + vcsel_period_pclks: number, + ): number { let macroPeriod = this.calcMacroPeriod(vcsel_period_pclks); - return ((timeout_period_mclks * macroPeriod) + (macroPeriod / 2)) / 1000 + return (timeout_period_mclks * macroPeriod + macroPeriod / 2) / 1000; } private calcMacroPeriod(vcsel_period_pclks: number): number { - return (((2304 * (vcsel_period_pclks) * 1655) + 500) / 1000); + return (2304 * vcsel_period_pclks * 1655 + 500) / 1000; } private async getSequenceStepEnables(): Promise { let result = new SequenceStepEnables(); - let sequenceConfig = await this.readRegister(SYSTEM_SEQUENCE_CONFIG); + let sequenceConfig = await this.readRegister(register.SYSTEM_SEQUENCE_CONFIG); result.tcc = ((sequenceConfig >> 4) & 0x1) != 0; result.dss = ((sequenceConfig >> 3) & 0x1) != 0; @@ -428,23 +460,29 @@ export class VL53L0X { } private async setSignalRateLimit(mcps: number): Promise { - await this.writeShort(register.FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, (mcps * (1<<7))); + await this.writeShort( + register.FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, + mcps * (1 << 7), + ); } private async getSignalRateLimit(): Promise { - return (await this.readShort(register.FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT)) / (1 << 7); + return ( + (await this.readShort(register.FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT)) / + (1 << 7) + ); } // Get reference SPAD (single photon avalanche diode) count and type // based on VL53L0X_get_info_from_device() private async getSpadInfo() { await this.writeRegister(0x80, 0x01); - await this.writeRegister(0xFF, 0x01); + await this.writeRegister(0xff, 0x01); await this.writeRegister(0x00, 0x00); - await this.writeRegister(0xFF, 0x06); - await this.writeRegister(0x83, await this.readRegister(0x83) | 0x04); - await this.writeRegister(0xFF, 0x07); + await this.writeRegister(0xff, 0x06); + await this.writeRegister(0x83, (await this.readRegister(0x83)) | 0x04); + await this.writeRegister(0xff, 0x07); await this.writeRegister(0x81, 0x01); await this.writeRegister(0x80, 0x01); @@ -453,7 +491,7 @@ export class VL53L0X { await this.writeRegister(0x83, 0x00); //wait for the device to be ready - while(await this.readRegister(0x83) == 0); + while ((await this.readRegister(0x83)) == 0); await this.writeRegister(0x83, 0x01); let tmp = await this.readRegister(0x92); @@ -477,11 +515,23 @@ export class VL53L0X { } private async readMultipleBytes(register: number, n: number): Promise { - return await readRegisterMultipleBytes(this.hub, this.channel, this.address, register, n); + return await readRegisterMultipleBytes( + this.hub, + this.channel, + this.address, + register, + n, + ); } private async writeMultipleBytes(register: number, values: number[]): Promise { - return await writeRegisterMultipleBytes(this.hub, this.channel, this.address, register, values); + return await writeRegisterMultipleBytes( + this.hub, + this.channel, + this.address, + register, + values, + ); } private async writeRegister(register: number, value: number) { @@ -519,4 +569,3 @@ class SequenceStepTimeouts { pre_range_us = 0; final_range_us = 0; } - From 6cd64b3f86b168e4e39bcd0b85033c55cfd303b8 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Thu, 25 May 2023 10:17:41 -0500 Subject: [PATCH 086/148] Add continuous flag to distance command --- .../src/{commands => command}/digital.ts | 0 packages/sample/src/command/distance.ts | 24 +++++++++ packages/sample/src/main.ts | 54 +++++-------------- 3 files changed, 36 insertions(+), 42 deletions(-) rename packages/sample/src/{commands => command}/digital.ts (100%) create mode 100644 packages/sample/src/command/distance.ts diff --git a/packages/sample/src/commands/digital.ts b/packages/sample/src/command/digital.ts similarity index 100% rename from packages/sample/src/commands/digital.ts rename to packages/sample/src/command/digital.ts diff --git a/packages/sample/src/command/distance.ts b/packages/sample/src/command/distance.ts new file mode 100644 index 00000000..cc863ce2 --- /dev/null +++ b/packages/sample/src/command/distance.ts @@ -0,0 +1,24 @@ +import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; +import { DistanceSensor } from "@rev-robotics/distance-sensor"; + +export async function distance(channel: number, isContinuous: boolean) { + console.log(`Channel number is ${channel}`); + + let hubs = await openConnectedExpansionHubs(); + let hub = hubs[0]; + + let sensor = new DistanceSensor(hub, channel); + await sensor.setup(); + + if (isContinuous) { + sensor.startMeasuringDistance((distance) => { + console.log(`Distance is ${distance}mm`); + }, 1000); + } else { + let distance = await sensor.getDistanceMillimeters(); + console.log(`Distance is ${distance}mm`); + + sensor.stop(); + hub.close(); + } +} diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 5e43ab63..6b569ccd 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -23,7 +23,8 @@ import { openHubWithAddress, openParentExpansionHub, } from "@rev-robotics/expansion-hub"; -import { digitalRead, digitalWrite } from "./commands/digital.js"; +import { digitalRead, digitalWrite } from "./command/digital.js"; +import { distance } from "./command/distance.js"; const program = new Command(); @@ -40,7 +41,6 @@ program let digitalCommand = program.command("digital"); -<<<<<<< HEAD digitalCommand .command("write ") .description("write digital pin. Valid values for are high, low, 0, and 1.") @@ -53,46 +53,6 @@ digitalCommand stateBoolean = false; } else { program.error("Please provide only one of {high, low, 1, 0}"); -======= -if(options.list) { - console.log("Starting to search Serial Ports") - const hubs: ExpansionHub[] = await getConnectedExpansionHubs(); - hubs.forEach(async (hub) => { - hub.on("error", (e: any) => { - console.log(`Got error:`); - console.log(e); - }); - console.log(await toString(hub)); - }); -} - -if(options.distance) { - let channel = Number(options.distance) - console.log(`Channel number is ${channel}`); - - let hubs = await getConnectedExpansionHubs(); - let hub = hubs[0]; - - let sensor = new DistanceSensor(hub, channel); - await sensor.setup(); - - sensor.startMeasuringDistance((distance) => { - console.log(`Distance is ${distance}mm`); - }, 1000); - - setTimeout(async () => { - sensor.stop(); - hub.close(); - }, 20000); -} - -async function toString(hub: RevHub): Promise { - let result = `RevHub: ${hub.moduleAddress}\n`; - - if(hub.isParent()) { - for(const child of hub.getChildren()) { - result += `\tRevHub: ${child.moduleAddress}\n`; ->>>>>>> fb77285 (Abstract away the driver, providing a lighter-weight DistanceSensor class.) } let digitalState = stateBoolean ? DigitalState.High : DigitalState.Low; @@ -270,6 +230,16 @@ program await runServo(hub, channelValue, pulseWidthValue, frameWidthValue); }); +program + .command("distance ") + .option("--continuous", "run continuously") + .description("Read distance from a REV 2m distance sensor") + .action(async (channel, options): Promise => { + let isContinuous = options.continuous !== undefined; + let channelNumber = Number(channel); + await distance(channelNumber, isContinuous); + }); + program.parse(process.argv); async function getExpansionHubOrThrow(): Promise { From 7a5cbeb3d452544a592417a76a71c16f749a0e63 Mon Sep 17 00:00:00 2001 From: Landry Norris <37489471+LandryNorris@users.noreply.github.com> Date: Wed, 7 Jun 2023 09:04:24 -0500 Subject: [PATCH 087/148] Update module description Co-authored-by: Noah Andrews --- packages/distance-sensor/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/distance-sensor/package.json b/packages/distance-sensor/package.json index 4cf357fc..7ac0b72b 100644 --- a/packages/distance-sensor/package.json +++ b/packages/distance-sensor/package.json @@ -1,7 +1,7 @@ { "name": "@rev-robotics/distance-sensor", "version": "0.1.0", - "description": "Library for using the REV Robotics 2m distance sensor", + "description": "Library for using the REV Robotics 2m distance sensor with a REV Robotics Control Hub or Expansion Hub", "main": "dist/index.js", "type": "module", "dependencies": { From 9f79dca4f702a7b7ff4142cff3f56638cd9ec764 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 7 Jun 2023 12:02:49 -0500 Subject: [PATCH 088/148] depend on specific versions of other libraries --- package-lock.json | 6 +++--- packages/distance-sensor/package.json | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7781c0cd..ed1f0fc1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7834,9 +7834,9 @@ }, "packages/distance-sensor": { "name": "@rev-robotics/distance-sensor", - "version": "0.1.0", + "version": "1.0.0", "dependencies": { - "@rev-robotics/expansion-hub": "*", + "@rev-robotics/rev-hub-core": "^1.0.0", "serialport": "^10.5.0" }, "devDependencies": { @@ -9212,7 +9212,7 @@ "@rev-robotics/distance-sensor": { "version": "file:packages/distance-sensor", "requires": { - "@rev-robotics/expansion-hub": "*", + "@rev-robotics/rev-hub-core": "^1.0.0", "@types/node": "^16.18.18", "serialport": "^10.5.0", "typescript": "^5.0.2" diff --git a/packages/distance-sensor/package.json b/packages/distance-sensor/package.json index 7ac0b72b..199c3e84 100644 --- a/packages/distance-sensor/package.json +++ b/packages/distance-sensor/package.json @@ -1,12 +1,12 @@ { "name": "@rev-robotics/distance-sensor", - "version": "0.1.0", + "version": "1.0.0", "description": "Library for using the REV Robotics 2m distance sensor with a REV Robotics Control Hub or Expansion Hub", "main": "dist/index.js", "type": "module", "dependencies": { "serialport": "^10.5.0", - "@rev-robotics/expansion-hub": "*" + "@rev-robotics/rev-hub-core": "^1.0.0" }, "devDependencies": { "@types/node": "^16.18.18", From 2fe4774b03874196e3262ee5d31ed55db74e8a11 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 7 Jun 2023 12:21:01 -0500 Subject: [PATCH 089/148] higher-level I2C methods --- packages/control-hub/src/discovery.ts | 2 +- .../control-hub/src/internal/ControlHub.ts | 18 +++++- .../src/internal/ControlHubConnected.ts | 21 +++++-- packages/core/src/ExpansionHub.ts | 39 ++++++++++-- packages/distance-sensor/src/i2c-utils.ts | 10 +-- .../src/internal/ExpansionHub.ts | 61 +++++++++++++++---- 6 files changed, 117 insertions(+), 34 deletions(-) diff --git a/packages/control-hub/src/discovery.ts b/packages/control-hub/src/discovery.ts index bb85d757..7e2cd577 100644 --- a/packages/control-hub/src/discovery.ts +++ b/packages/control-hub/src/discovery.ts @@ -1,5 +1,5 @@ import { ControlHubInternal } from "./internal/ControlHub.js"; -import { ControlHub } from "@rev-robotics/rev-hub-core"; +import { ControlHub, ExpansionHub } from "@rev-robotics/rev-hub-core"; export async function openConnectedControlHub(): Promise { try { diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 1a6ef7ed..8e34024c 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -353,11 +353,25 @@ export class ControlHubInternal implements ControlHub { return this.embedded.queryInterface(interfaceName); } + readI2CRegister( + i2cChannel: number, + targetAddress: number, + numBytesToRead: number, + register: number, + ): Promise { + return this.embedded.readI2CRegister( + i2cChannel, + targetAddress, + numBytesToRead, + register, + ); + } + readI2CMultipleBytes( i2cChannel: number, slaveAddress: number, numBytesToRead: number, - ): Promise { + ): Promise { return this.embedded.readI2CMultipleBytes( i2cChannel, slaveAddress, @@ -365,7 +379,7 @@ export class ControlHubInternal implements ControlHub { ); } - readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise { + readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise { return this.embedded.readI2CSingleByte(i2cChannel, slaveAddress); } diff --git a/packages/control-hub/src/internal/ControlHubConnected.ts b/packages/control-hub/src/internal/ControlHubConnected.ts index 54f881e1..d6164b4e 100644 --- a/packages/control-hub/src/internal/ControlHubConnected.ts +++ b/packages/control-hub/src/internal/ControlHubConnected.ts @@ -347,15 +347,24 @@ export class ControlHubConnected implements ParentExpansionHub { }; } + readI2CRegister( + i2cChannel: number, + targetAddress: number, + numBytesToRead: number, + register: number, + ): Promise { + throw new Error("not implemented"); + } + readI2CMultipleBytes( i2cChannel: number, - slaveAddress: number, + targetAddress: number, numBytesToRead: number, - ): Promise { + ): Promise { throw new Error("not implemented"); } - readI2CSingleByte(i2cChannel: number, slaveAddress: number): Promise { + readI2CSingleByte(i2cChannel: number, targetAddress: number): Promise { throw new Error("not implemented"); } @@ -598,7 +607,7 @@ export class ControlHubConnected implements ParentExpansionHub { writeI2CMultipleBytes( i2cChannel: number, - slaveAddress: number, + targetAddress: number, bytes: number[], ): Promise { throw new Error("not implemented"); @@ -606,7 +615,7 @@ export class ControlHubConnected implements ParentExpansionHub { writeI2CReadMultipleBytes( i2cChannel: number, - slaveAddress: number, + targetAddress: number, numBytesToRead: number, startAddress: number, ): Promise { @@ -615,7 +624,7 @@ export class ControlHubConnected implements ParentExpansionHub { writeI2CSingleByte( i2cChannel: number, - slaveAddress: number, + targetAddress: number, byte: number, ): Promise { throw new Error("not implemented"); diff --git a/packages/core/src/ExpansionHub.ts b/packages/core/src/ExpansionHub.ts index d7007c25..841430b0 100644 --- a/packages/core/src/ExpansionHub.ts +++ b/packages/core/src/ExpansionHub.ts @@ -152,18 +152,47 @@ export interface ExpansionHub extends RevHub { bytes: number[], ): Promise; getI2CWriteStatus(i2cChannel: number): Promise; - readI2CSingleByte(i2cChannel: number, targetAddress: number): Promise; + + /** + * Read a single byte from a target device. Use {@link getI2CReadStatus} to + * get the actual byte. + * @param i2cChannel + * @param targetAddress the address of the target device + */ + readI2CSingleByte(i2cChannel: number, targetAddress: number): Promise; + + /** + * Read multiple bytes from a target device. Use {@link getI2CReadStatus} to + * get the actual data. + * @param i2cChannel + * @param targetAddress the address of the target device + * @param numBytesToRead the size of the payload to read + */ readI2CMultipleBytes( i2cChannel: number, targetAddress: number, numBytesToRead: number, - ): Promise; - writeI2CReadMultipleBytes( + ): Promise; + + /** + * Send a write command to a given target requesting data at a given register. + * @param i2cChannel + * @param targetAddress the address of the target device + * @param numBytesToRead size of data to read + * @param register a byte to send at the start of the payload, typically a register address. + */ + readI2CRegister( i2cChannel: number, targetAddress: number, numBytesToRead: number, - startAddress: number, - ): Promise; + register: number, + ): Promise; + + /** + * Get the read status, indicating whether a read was successful and how + * much data was read. + * @param i2cChannel + */ getI2CReadStatus(i2cChannel: number): Promise; // Motor diff --git a/packages/distance-sensor/src/i2c-utils.ts b/packages/distance-sensor/src/i2c-utils.ts index 79ea052b..48ba765d 100644 --- a/packages/distance-sensor/src/i2c-utils.ts +++ b/packages/distance-sensor/src/i2c-utils.ts @@ -6,10 +6,7 @@ export async function readRegister( address: number, register: number, ): Promise { - await hub.writeI2CSingleByte(channel, address, register); - await hub.readI2CSingleByte(channel, address); - - return (await hub.getI2CReadStatus(channel)).bytes[0]; + return (await hub.readI2CRegister(channel, address, 1, register))[0]; } export async function readRegisterMultipleBytes( @@ -19,10 +16,7 @@ export async function readRegisterMultipleBytes( register: number, n: number, ): Promise { - await hub.writeI2CSingleByte(channel, address, register); - await hub.readI2CMultipleBytes(channel, address, n); - - return (await hub.getI2CReadStatus(channel)).bytes; + return await hub.readI2CRegister(channel, address, n, register); } export async function writeRegisterMultipleBytes( diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index 7533f0a3..3eb0fd09 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -31,6 +31,7 @@ import { ParameterOutOfRangeError, GeneralSerialError, CommandNotSupportedError, + I2cOperationInProgressError, } from "@rev-robotics/rev-hub-core"; import { closeSerialPort } from "../open-rev-hub.js"; import { EventEmitter } from "events"; @@ -374,19 +375,43 @@ export class ExpansionHubInternal implements ExpansionHub { i2cChannel: number, targetAddress: number, numBytesToRead: number, - ): Promise { - return this.convertErrorPromise(() => { - return this.nativeRevHub.readI2CMultipleBytes( + ): Promise { + return this.convertErrorPromise(async () => { + await this.nativeRevHub.readI2CMultipleBytes( i2cChannel, targetAddress, numBytesToRead, ); + while (true) { + try { + let status: I2CReadStatus = await this.nativeRevHub.getI2CReadStatus( + i2cChannel, + ); + return status.bytes; + } catch (e) { + if (e! instanceof I2cOperationInProgressError) { + throw e; + } + } + } }); } - readI2CSingleByte(i2cChannel: number, targetAddress: number): Promise { - return this.convertErrorPromise(() => { - return this.nativeRevHub.readI2CSingleByte(i2cChannel, targetAddress); + readI2CSingleByte(i2cChannel: number, targetAddress: number): Promise { + return this.convertErrorPromise(async () => { + await this.nativeRevHub.readI2CSingleByte(i2cChannel, targetAddress); + while (true) { + try { + let status: I2CReadStatus = await this.nativeRevHub.getI2CReadStatus( + i2cChannel, + ); + return status.bytes[0]; + } catch (e) { + if (e! instanceof I2cOperationInProgressError) { + throw e; + } + } + } }); } @@ -618,19 +643,31 @@ export class ExpansionHubInternal implements ExpansionHub { }); } - writeI2CReadMultipleBytes( + readI2CRegister( i2cChannel: number, targetAddress: number, numBytesToRead: number, - startAddress: number, - ): Promise { - return this.convertErrorPromise(() => { - return this.nativeRevHub.writeI2CReadMultipleBytes( + register: number, + ): Promise { + return this.convertErrorPromise(async () => { + await this.nativeRevHub.writeI2CReadMultipleBytes( i2cChannel, targetAddress, numBytesToRead, - startAddress, + register, ); + while (true) { + try { + let status: I2CReadStatus = await this.nativeRevHub.getI2CReadStatus( + i2cChannel, + ); + return status.bytes; + } catch (e) { + if (e! instanceof I2cOperationInProgressError) { + throw e; + } + } + } }); } From eee9bbae7c609a9c7671f0d367c850464e73bc47 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Mon, 12 Jun 2023 16:13:13 -0500 Subject: [PATCH 090/148] Add i2c methods for distance sensor --- packages/control-hub/src/internal/ControlHub.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 8e34024c..241307e5 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -547,7 +547,7 @@ export class ControlHubInternal implements ControlHub { ); } - writeI2CSingleByte( + async writeI2CSingleByte( i2cChannel: number, slaveAddress: number, byte: number, From 96316a718ed096c6a8588a61ad2430bb94ab164a Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 13 Jun 2023 09:56:31 -0500 Subject: [PATCH 091/148] update to work with latest control hub --- packages/control-hub/src/internal/ControlHub.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 241307e5..e2e0a8e3 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -78,7 +78,6 @@ export class ControlHubInternal implements ControlHub { async open(ip: string = "192.168.43.1", port: string = "8081"): Promise { this.webSocketConnection = new WebSocket(`ws://${ip}:${port}`); - console.log(`Opening on port ${port}`); this.webSocketConnection.on("message", (data) => { let rawMessage = JSON.parse(data.toString()); @@ -105,7 +104,7 @@ export class ControlHubInternal implements ControlHub { this.webSocketConnection.on("error", (_: WebSocket, err: Error) => { console.log("Websocket error"); - console.log(err); + console.error(err); this.isConnected = false; }); From 21c56d73a86740a8713e84b78e39237ee19b6c5e Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 13 Jun 2023 11:07:03 -0500 Subject: [PATCH 092/148] pass in hub for servo command --- packages/sample/src/command/servo.ts | 4 ++-- packages/sample/src/main.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/sample/src/command/servo.ts b/packages/sample/src/command/servo.ts index 240715f0..6697fbad 100644 --- a/packages/sample/src/command/servo.ts +++ b/packages/sample/src/command/servo.ts @@ -10,7 +10,7 @@ export async function runServo( await hub.setServoPulseWidth(channel, pulseWidth); await hub.setServoEnable(channel, true); - setTimeout(() => { + process.on("SIGINT", () => { hub.close(); - }, 10000); + }); } diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 6b569ccd..c16cbbba 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -224,7 +224,6 @@ program let channelValue = Number(channel); let pulseWidthValue = Number(pulseWidth); let frameWidthValue = frameWidth ? Number(frameWidth) : 4000; - let hub = await getExpansionHubOrThrow(); await runServo(hub, channelValue, pulseWidthValue, frameWidthValue); From 12f920bcfa358d04c4652144d2fcb2d77f936cbc Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 14 Jun 2023 12:30:19 -0500 Subject: [PATCH 093/148] add bulk input command --- .../control-hub/src/internal/ControlHub.ts | 46 ++++++++++++++ packages/core/src/RevHub.ts | 7 +++ packages/sample/src/command/bulkinput.ts | 7 +++ packages/sample/src/command/digital.ts | 45 +++++++------- packages/sample/src/command/distance.ts | 2 +- packages/sample/src/main.ts | 62 +++++++++++-------- 6 files changed, 119 insertions(+), 50 deletions(-) create mode 100644 packages/sample/src/command/bulkinput.ts diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index e2e0a8e3..a1895b79 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -30,7 +30,11 @@ import { ControlHubConnected } from "./ControlHubConnected.js"; export class ControlHubInternal implements ControlHub { readonly isOpen: boolean = true; +<<<<<<< HEAD readonly moduleAddress: number = 173; +======= + moduleAddress: number = 173; +>>>>>>> 9da9a17 (add bulk input command) responseTimeoutMs: number = 0; type: RevHubType = RevHubType.ControlHub; readonly serialNumber: string; @@ -227,7 +231,31 @@ export class ControlHubInternal implements ControlHub { } async getBulkInputData(): Promise { +<<<<<<< HEAD return this.embedded.getBulkInputData(); +======= + let response: any = await this.sendCommand("getBulkInputData", { + id: this.id, + }); + + return { + digitalInputs: response.digitalInputs, + motor0position_enc: response.motor0EncoderCounts, + motor1position_enc: response.motor1EncoderCounts, + motor2position_enc: response.motor2EncoderCounts, + motor3position_enc: response.motor3EncoderCounts, + motorStatus: response.motorStatus, + motor0velocity_cps: response.motor0Velocity, + motor1velocity_cps: response.motor1Velocity, + motor2velocity_cps: response.motor2Velocity, + motor3velocity_cps: response.motor3Velocity, + analog0_mV: response.analog0mV, + analog1_mV: response.analog1mV, + analog2_mV: response.analog2mV, + analog3_mV: response.analog3mV, + attentionRequired: 0, + }; +>>>>>>> 9da9a17 (add bulk input command) } async getAllDigitalInputs(): Promise { @@ -426,7 +454,15 @@ export class ControlHubInternal implements ControlHub { } async setDigitalOutput(dioPin: number, value: DigitalState): Promise { +<<<<<<< HEAD return this.embedded.setDigitalOutput(dioPin, value); +======= + await this.sendCommand("readVersionString", { + id: this.id, + pin: dioPin, + value: value.isHigh() ?? false, + }); +>>>>>>> 9da9a17 (add bulk input command) } async setFTDIResetControl(ftdiResetControl: boolean): Promise { @@ -561,6 +597,7 @@ export class ControlHubInternal implements ControlHub { async addHubBySerialNumberAndAddress( serialNumber: string, moduleAddress: number, +<<<<<<< HEAD ): Promise { let id = await this.openHub(serialNumber, moduleAddress, moduleAddress); @@ -580,6 +617,15 @@ export class ControlHubInternal implements ControlHub { throw new Error("A child hub with a serial number must also be a parent."); } return newHub; +======= + parentAddress: number = moduleAddress, + ): Promise { + return await this.sendCommand("openHub", { + parentSerialNumber: serialNumber, + parentHubAddress: parentAddress, + hubAddress: moduleAddress, + }); +>>>>>>> 9da9a17 (add bulk input command) } async sendCommand(type: string, params: P, timeout: number = 1000): Promise { diff --git a/packages/core/src/RevHub.ts b/packages/core/src/RevHub.ts index ded4fdff..ce927847 100644 --- a/packages/core/src/RevHub.ts +++ b/packages/core/src/RevHub.ts @@ -18,6 +18,13 @@ export interface RevHub { } export interface ParentRevHub extends RevHub { + /** + * This only contains directly-connected children (all devices in an RS-485 + * daisy chain count as directly-connected). If any devices in this array + * are themselves parents (call {@link RevHub.isParent}), their children + * will not be included, and you will need to access their + * {@link ParentRevHub.children} property. + */ readonly children: ReadonlyArray; readonly serialNumber: string; diff --git a/packages/sample/src/command/bulkinput.ts b/packages/sample/src/command/bulkinput.ts new file mode 100644 index 00000000..3882d766 --- /dev/null +++ b/packages/sample/src/command/bulkinput.ts @@ -0,0 +1,7 @@ +import { ExpansionHub } from "@rev-robotics/rev-hub-core"; + +export async function getBulkInputData(hub: ExpansionHub): Promise { + let data = await hub.getBulkInputData(); + + console.log(JSON.stringify(data)); +} diff --git a/packages/sample/src/command/digital.ts b/packages/sample/src/command/digital.ts index 1c054dce..3237addf 100644 --- a/packages/sample/src/command/digital.ts +++ b/packages/sample/src/command/digital.ts @@ -1,34 +1,35 @@ -import { DioDirection } from "@rev-robotics/rhsplib"; -import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; -import { DigitalState } from "@rev-robotics/rev-hub-core"; +import { + DigitalChannelDirection, + DigitalState, + DioDirection, + ExpansionHub, +} from "@rev-robotics/rev-hub-core"; -export async function digitalRead(channel: number, continuous: boolean): Promise { - let hubs = await openConnectedExpansionHubs(); - - await hubs[0].setDigitalDirection(channel, DioDirection.Input); +export async function digitalRead( + hub: ExpansionHub, + channel: number, + continuous: boolean, +): Promise { + await hub.setDigitalDirection(channel, DioDirection.Input); if (continuous) { while (true) { - let state = await hubs[0].getDigitalInput(channel); + let state = await hub.getDigitalInput(channel); console.log(`${state}`); } } else { - let state = await hubs[0].getDigitalInput(channel); + let state = await hub.getDigitalInput(channel); console.log(`${state}`); } - - for (let hub of hubs) { - hub.close(); - } + hub.close(); } -export async function digitalWrite(channel: number, state: DigitalState): Promise { - let hubs = await openConnectedExpansionHubs(); - - await hubs[0].setDigitalDirection(channel, DioDirection.Output); - await hubs[0].setDigitalOutput(channel, state); - - for (let hub of hubs) { - hub.close(); - } +export async function digitalWrite( + hub: ExpansionHub, + channel: number, + state: DigitalState, +): Promise { + await hub.setDigitalDirection(channel, DioDirection.Output); + await hub.setDigitalOutput(channel, state); + hub.close(); } diff --git a/packages/sample/src/command/distance.ts b/packages/sample/src/command/distance.ts index cc863ce2..b36b8dba 100644 --- a/packages/sample/src/command/distance.ts +++ b/packages/sample/src/command/distance.ts @@ -13,7 +13,7 @@ export async function distance(channel: number, isContinuous: boolean) { if (isContinuous) { sensor.startMeasuringDistance((distance) => { console.log(`Distance is ${distance}mm`); - }, 1000); + }, 10); } else { let distance = await sensor.getDistanceMillimeters(); console.log(`Distance is ${distance}mm`); diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index c16cbbba..cd0b098a 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -25,6 +25,7 @@ import { } from "@rev-robotics/expansion-hub"; import { digitalRead, digitalWrite } from "./command/digital.js"; import { distance } from "./command/distance.js"; +import { getBulkInputData } from "./command/bulkinput.js"; const program = new Command(); @@ -39,6 +40,36 @@ program "module address. If this is specified, you must also specify a parent address", ); +program + .command("testErrorHandling") + .description( + "Intentionally causes a few errors to happen and " + + "prints information about the errors.", + ) + .action(async () => { + await error(); + }); + +program + .command("list") + .description("List all connected expansion hubs") + .action(async () => { + await list(); + }); + +program + .command("led") + .description("Run LED steps") + .action(async () => { + let hub = await getExpansionHubOrThrow(); + await led(hub); + }); + +program.command("bulk input").action(async () => { + let hubs = await openUsbControlHubs(); + await getBulkInputData(hubs[0]); +}); + let digitalCommand = program.command("digital"); digitalCommand @@ -55,8 +86,9 @@ digitalCommand program.error("Please provide only one of {high, low, 1, 0}"); } let digitalState = stateBoolean ? DigitalState.High : DigitalState.Low; + let hubs = await openUsbControlHubs(); - await digitalWrite(channelNumber, digitalState); + await digitalWrite(hubs[0], channelNumber, digitalState); }); digitalCommand @@ -66,33 +98,9 @@ digitalCommand .action(async (channel, options) => { let isContinuous = options.continuous !== undefined; let channelNumber = Number(channel); + let hubs = await openUsbControlHubs(); - await digitalRead(channelNumber, isContinuous); - }); - -program - .command("testErrorHandling") - .description( - "Intentionally causes a few errors to happen and " + - "prints information about the errors.", - ) - .action(async () => { - await error(); - }); - -program - .command("list") - .description("List all connected expansion hubs") - .action(async () => { - await list(); - }); - -program - .command("led") - .description("Run LED steps") - .action(async () => { - let hub = await getExpansionHubOrThrow(); - await led(hub); + await digitalRead(hubs[0], channelNumber, isContinuous); }); let motorCommand = program.command("motor"); From fc8992b55fbe414e49f22fb1f00781f73376fc49 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Wed, 14 Jun 2023 15:01:40 -0500 Subject: [PATCH 094/148] refine LED commands --- .../control-hub/src/internal/ControlHub.ts | 47 +------------------ .../src/command/{led.ts => ledPattern.ts} | 19 ++++++-- packages/sample/src/main.ts | 26 +++++----- 3 files changed, 32 insertions(+), 60 deletions(-) rename packages/sample/src/command/{led.ts => ledPattern.ts} (55%) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index a1895b79..e9b64152 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -30,11 +30,7 @@ import { ControlHubConnected } from "./ControlHubConnected.js"; export class ControlHubInternal implements ControlHub { readonly isOpen: boolean = true; -<<<<<<< HEAD readonly moduleAddress: number = 173; -======= - moduleAddress: number = 173; ->>>>>>> 9da9a17 (add bulk input command) responseTimeoutMs: number = 0; type: RevHubType = RevHubType.ControlHub; readonly serialNumber: string; @@ -81,6 +77,7 @@ export class ControlHubInternal implements ControlHub { } async open(ip: string = "192.168.43.1", port: string = "8081"): Promise { + console.log(`Port is ${port}`); this.webSocketConnection = new WebSocket(`ws://${ip}:${port}`); this.webSocketConnection.on("message", (data) => { @@ -231,31 +228,7 @@ export class ControlHubInternal implements ControlHub { } async getBulkInputData(): Promise { -<<<<<<< HEAD return this.embedded.getBulkInputData(); -======= - let response: any = await this.sendCommand("getBulkInputData", { - id: this.id, - }); - - return { - digitalInputs: response.digitalInputs, - motor0position_enc: response.motor0EncoderCounts, - motor1position_enc: response.motor1EncoderCounts, - motor2position_enc: response.motor2EncoderCounts, - motor3position_enc: response.motor3EncoderCounts, - motorStatus: response.motorStatus, - motor0velocity_cps: response.motor0Velocity, - motor1velocity_cps: response.motor1Velocity, - motor2velocity_cps: response.motor2Velocity, - motor3velocity_cps: response.motor3Velocity, - analog0_mV: response.analog0mV, - analog1_mV: response.analog1mV, - analog2_mV: response.analog2mV, - analog3_mV: response.analog3mV, - attentionRequired: 0, - }; ->>>>>>> 9da9a17 (add bulk input command) } async getAllDigitalInputs(): Promise { @@ -454,15 +427,7 @@ export class ControlHubInternal implements ControlHub { } async setDigitalOutput(dioPin: number, value: DigitalState): Promise { -<<<<<<< HEAD return this.embedded.setDigitalOutput(dioPin, value); -======= - await this.sendCommand("readVersionString", { - id: this.id, - pin: dioPin, - value: value.isHigh() ?? false, - }); ->>>>>>> 9da9a17 (add bulk input command) } async setFTDIResetControl(ftdiResetControl: boolean): Promise { @@ -597,7 +562,6 @@ export class ControlHubInternal implements ControlHub { async addHubBySerialNumberAndAddress( serialNumber: string, moduleAddress: number, -<<<<<<< HEAD ): Promise { let id = await this.openHub(serialNumber, moduleAddress, moduleAddress); @@ -617,15 +581,6 @@ export class ControlHubInternal implements ControlHub { throw new Error("A child hub with a serial number must also be a parent."); } return newHub; -======= - parentAddress: number = moduleAddress, - ): Promise { - return await this.sendCommand("openHub", { - parentSerialNumber: serialNumber, - parentHubAddress: parentAddress, - hubAddress: moduleAddress, - }); ->>>>>>> 9da9a17 (add bulk input command) } async sendCommand(type: string, params: P, timeout: number = 1000): Promise { diff --git a/packages/sample/src/command/led.ts b/packages/sample/src/command/ledPattern.ts similarity index 55% rename from packages/sample/src/command/led.ts rename to packages/sample/src/command/ledPattern.ts index 0f0ccaa7..76871351 100644 --- a/packages/sample/src/command/led.ts +++ b/packages/sample/src/command/ledPattern.ts @@ -1,8 +1,11 @@ -import { createLedPattern, LedPatternStep } from "@rev-robotics/expansion-hub"; +import { + createLedPattern, + LedPatternStep, + openConnectedExpansionHubs, +} from "@rev-robotics/expansion-hub"; import { ExpansionHub } from "@rev-robotics/rev-hub-core"; import { openUsbControlHubs } from "../adb-setup.js"; - -export async function led(hub: ExpansionHub) { +export async function ledPattern(hub: ExpansionHub) { const steps = [ new LedPatternStep(1, 0, 255, 0), //green new LedPatternStep(1, 255, 0, 0), //red @@ -14,3 +17,13 @@ export async function led(hub: ExpansionHub) { await hub.setModuleLedPattern(pattern); } + +export async function led( + hub: ExpansionHub, + r: number, + g: number, + b: number, +): Promise { + console.log(`Setting color to ${r} ${g}, ${b}`); + await hub.setModuleLedColor(r, g, b); +} diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index cd0b098a..4cb1bd2a 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -9,7 +9,7 @@ import { runMotorToPosition, } from "./command/motor.js"; import { list } from "./command/list.js"; -import { led } from "./command/led.js"; +import { led, ledPattern } from "./command/ledPattern.js"; import { runServo } from "./command/servo.js"; import { openUsbControlHubs } from "./adb-setup.js"; import { @@ -58,11 +58,23 @@ program }); program - .command("led") + .command("pattern") .description("Run LED steps") .action(async () => { let hub = await getExpansionHubOrThrow(); - await led(hub); + await ledPattern(hub); + }); + +program + .command("led ") + .description("Set LED color") + .action(async (r, g, b) => { + console.log("Running led color"); + let hubs = await openUsbControlHubs(); + let rValue = Number(r); + let gValue = Number(g); + let bValue = Number(b); + await led(hubs[0], rValue, gValue, bValue); }); program.command("bulk input").action(async () => { @@ -166,14 +178,6 @@ program await list(); }); -program - .command("led") - .description("Run LED steps") - .action(async () => { - let hub = await getExpansionHubOrThrow(); - await led(hub); - }); - program .command("analog ") .option("--continuous", "Run continuously") From b6bfb6e2d56bb69e5717831d14d89135e23e919e Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 16 Jun 2023 12:30:50 -0500 Subject: [PATCH 095/148] exit process when sigint --- packages/sample/src/command/servo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/sample/src/command/servo.ts b/packages/sample/src/command/servo.ts index 6697fbad..a84677d1 100644 --- a/packages/sample/src/command/servo.ts +++ b/packages/sample/src/command/servo.ts @@ -12,5 +12,6 @@ export async function runServo( process.on("SIGINT", () => { hub.close(); + process.exit(); }); } From 4a7dd7bd51fc09304aea6d6b091cae975ad883f6 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 16 Jun 2023 13:17:03 -0500 Subject: [PATCH 096/148] apply latest control hub changes --- .../src/internal/ControlHubConnected.ts | 165 +++++++++--------- packages/sample/package.json | 2 +- packages/sample/src/command/motor.ts | 39 ++--- packages/sample/src/main.ts | 13 +- 4 files changed, 111 insertions(+), 108 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHubConnected.ts b/packages/control-hub/src/internal/ControlHubConnected.ts index d6164b4e..e44f871e 100644 --- a/packages/control-hub/src/internal/ControlHubConnected.ts +++ b/packages/control-hub/src/internal/ControlHubConnected.ts @@ -58,75 +58,75 @@ export class ControlHubConnected implements ParentExpansionHub { async getAnalogInput(channel: number): Promise { return await this.sendCommand("getAnalogInput", { - id: this.id, + hId: this.id, analogChannel: channel, }); } async get5VBusVoltage(): Promise { return await this.sendCommand("get5VBusVoltage", { - id: this.id, + hId: this.id, }); } async getBatteryCurrent(): Promise { return await this.sendCommand("getBatteryCurrent", { - id: this.id, + hId: this.id, }); } async getBatteryVoltage(): Promise { return await this.sendCommand("getBatteryVoltage", { - id: this.id, + hId: this.id, }); } async getDigitalBusCurrent(): Promise { return await this.sendCommand("getDigitalBusCurrent", { - id: this.id, + hId: this.id, }); } async getI2CCurrent(): Promise { return await this.sendCommand("getI2CCurrent", { - id: this.id, + hId: this.id, }); } async getMotorCurrent(motorChannel: number): Promise { return await this.sendCommand("getMotorCurrent", { - id: this.id, - motorChannel: motorChannel, + hId: this.id, + c: motorChannel, }); } async getServoCurrent(): Promise { return await this.sendCommand("getMotorCurrent", { - id: this.id, + hId: this.id, }); } async getTemperature(): Promise { return await this.sendCommand("getTemperature", { - id: this.id, + hId: this.id, }); } async getBulkInputData(): Promise { return await this.sendCommand("getBulkInputData", { - id: this.id, + hId: this.id, }); } async getAllDigitalInputs(): Promise { return await this.sendCommand("getAllDigitalInputs", { - id: this.id, + hId: this.id, }); } async getDigitalDirection(dioPin: number): Promise { let isOutput = await this.sendCommand("getDigitalDirection", { - id: this.id, + hId: this.id, digitalChannel: dioPin, }); @@ -135,7 +135,7 @@ export class ControlHubConnected implements ParentExpansionHub { async getDigitalInput(dioPin: number): Promise { let result: boolean = await this.sendCommand("getDigitalInput", { - id: this.id, + hId: this.id, digitalChannel: dioPin, }); @@ -144,13 +144,13 @@ export class ControlHubConnected implements ParentExpansionHub { async getFTDIResetControl(): Promise { return await this.sendCommand("getFtdiResetControl", { - id: this.id, + hId: this.id, }); } async getI2CChannelConfiguration(i2cChannel: number): Promise { let speedCode = await this.sendCommand("getI2CChannelConfiguration", { - id: this.id, + hId: this.id, channel: i2cChannel, }); @@ -172,7 +172,7 @@ export class ControlHubConnected implements ParentExpansionHub { functionNumber: number, ): Promise { return await this.sendCommand("getInterfacePacketId", { - id: this.id, + hId: this.id, interfaceName: interfaceName, functionNumber: functionNumber, }); @@ -200,27 +200,27 @@ export class ControlHubConnected implements ParentExpansionHub { async getModuleStatus(clearStatusAfterResponse: boolean): Promise { return await this.sendCommand("getModuleStatus", { - id: this.id, + hId: this.id, }); } async getMotorAtTarget(motorChannel: number): Promise { return await this.sendCommand("getIsMotorAtTarget", { - id: this.id, + hId: this.id, }); } async getMotorChannelCurrentAlertLevel(motorChannel: number): Promise { return await this.sendCommand("getMotorAlertLevel", { - id: this.id, - motorChannel: motorChannel, + hId: this.id, + c: motorChannel, }); } async getMotorChannelEnable(motorChannel: number): Promise { return await this.sendCommand("getMotorChannelEnable", { - id: this.id, - motorChannel: motorChannel, + hId: this.id, + c: motorChannel, }); } @@ -228,22 +228,22 @@ export class ControlHubConnected implements ParentExpansionHub { motorChannel: number, ): Promise<{ motorMode: number; floatAtZero: boolean }> { return await this.sendCommand("getMotorMode", { - id: this.id, - motorChannel: motorChannel, + hId: this.id, + c: motorChannel, }); } async getMotorConstantPower(motorChannel: number): Promise { return await this.sendCommand("getMotorConstantPower", { - id: this.id, - motorChannel: motorChannel, + hId: this.id, + c: motorChannel, }); } async getMotorEncoderPosition(motorChannel: number): Promise { - return await this.sendCommand("getMotorEncoderPosition", { - id: this.id, - motorChannel: motorChannel, + return await this.sendCommand("getMotorEncoder", { + hId: this.id, + c: motorChannel, }); } @@ -256,7 +256,8 @@ export class ControlHubConnected implements ParentExpansionHub { { serialNumber: this.serialNumber, moduleAddress: this.moduleAddress, - motorChannel: motorChannel, + c: motorChannel, + m: motorMode, }, ); @@ -274,7 +275,7 @@ export class ControlHubConnected implements ParentExpansionHub { await this.sendCommand("getMotorTargetPosition", { serialNumber: this.serialNumber, moduleAddress: this.moduleAddress, - motorChannel: motorChannel, + c: motorChannel, }); return { @@ -285,41 +286,41 @@ export class ControlHubConnected implements ParentExpansionHub { async getMotorTargetVelocity(motorChannel: number): Promise { return await this.sendCommand("getMotorTargetVelocity", { - id: this.id, - motorChannel: motorChannel, + hId: this.id, + c: motorChannel, }); } async getPhoneChargeControl(): Promise { return await this.sendCommand("getPhoneChargeControl", { - id: this.id, + hId: this.id, }); } async getServoConfiguration(servoChannel: number): Promise { return await this.sendCommand("getServoConfiguration", { - id: this.id, - servoChannel: servoChannel, + hId: this.id, + c: servoChannel, }); } async getServoEnable(servoChannel: number): Promise { return await this.sendCommand("getServoEnable", { - id: this.id, - servoChannel: servoChannel, + hId: this.id, + c: servoChannel, }); } async getServoPulseWidth(servoChannel: number): Promise { return await this.sendCommand("getServoPulseWidth", { - id: this.id, - servoChannel: servoChannel, + hId: this.id, + c: servoChannel, }); } async injectDataLogHint(hintText: string): Promise { await this.sendCommand("injectDebugLogHint", { - id: this.id, + hId: this.id, hint: hintText, }); } @@ -376,20 +377,20 @@ export class ControlHubConnected implements ParentExpansionHub { async readVersionString(): Promise { return await this.sendCommand("readVersionString", { - id: this.id, + hId: this.id, }); } async resetMotorEncoder(motorChannel: number): Promise { await this.sendCommand("resetMotorEncoder", { - id: this.id, - motorChannel: motorChannel, + hId: this.id, + c: motorChannel, }); } async sendFailSafe(): Promise { await this.sendCommand("readVersionString", { - id: this.id, + hId: this.id, }); } @@ -408,7 +409,7 @@ export class ControlHubConnected implements ParentExpansionHub { verbosityLevel: VerbosityLevel, ): Promise { await this.sendCommand("readVersionString", { - id: this.id, + hId: this.id, debugGroup: debugGroup, verbosityLevel: verbosityLevel, }); @@ -416,14 +417,14 @@ export class ControlHubConnected implements ParentExpansionHub { async setAllDigitalOutputs(bitPackedField: number): Promise { await this.sendCommand("readVersionString", { - id: this.id, + hId: this.id, bitField: bitPackedField, }); } async setDigitalDirection(dioPin: number, direction: DioDirection): Promise { await this.sendCommand("readVersionString", { - id: this.id, + hId: this.id, pin: dioPin, isOutput: direction == DioDirection.Output, }); @@ -431,7 +432,7 @@ export class ControlHubConnected implements ParentExpansionHub { async setDigitalOutput(dioPin: number, value: DigitalState): Promise { await this.sendCommand("readVersionString", { - id: this.id, + hId: this.id, digitalChannel: dioPin, value: value.isHigh(), }); @@ -439,7 +440,7 @@ export class ControlHubConnected implements ParentExpansionHub { async setFTDIResetControl(ftdiResetControl: boolean): Promise { await this.sendCommand("setFtdiResetControl", { - id: this.id, + hId: this.id, }); } @@ -448,7 +449,7 @@ export class ControlHubConnected implements ParentExpansionHub { speedCode: I2CSpeedCode, ): Promise { await this.sendCommand("setI2CChannelConfiguration", { - id: this.id, + hId: this.id, i2cChannel: i2cChannel, speedCode: speedCode, }); @@ -456,7 +457,7 @@ export class ControlHubConnected implements ParentExpansionHub { async setModuleLedColor(red: number, green: number, blue: number): Promise { await this.sendCommand("setLedColor", { - id: this.id, + hId: this.id, r: red, g: green, b: blue, @@ -465,7 +466,7 @@ export class ControlHubConnected implements ParentExpansionHub { async setModuleLedPattern(ledPattern: LedPattern): Promise { await this.sendCommand("setLedPattern", { - id: this.id, + hId: this.id, rgbtPatternStep0: ledPattern.rgbtPatternStep0, rgbtPatternStep1: ledPattern.rgbtPatternStep1, rgbtPatternStep2: ledPattern.rgbtPatternStep2, @@ -490,16 +491,16 @@ export class ControlHubConnected implements ParentExpansionHub { currentLimit_mA: number, ): Promise { await this.sendCommand("setMotorAlertLevel", { - id: this.id, - motorChannel: motorChannel, - currentLimit_mA: currentLimit_mA, + hId: this.id, + c: motorChannel, + cl: currentLimit_mA, }); } async setMotorChannelEnable(motorChannel: number, enable: boolean): Promise { await this.sendCommand("setMotorEnabled", { - id: this.id, - motorChannel: motorChannel, + hId: this.id, + c: motorChannel, enable: enable, }); } @@ -509,19 +510,19 @@ export class ControlHubConnected implements ParentExpansionHub { motorMode: number, floatAtZero: boolean, ): Promise { - await this.sendCommand("setMotorChannelMode", { - id: this.id, - motorChannel: motorChannel, - motorMode: motorMode, - floatAtZero: floatAtZero, + await this.sendCommand("setMotorMode", { + hId: this.id, + c: motorChannel, + m: motorMode, + faz: floatAtZero, }); } async setMotorConstantPower(motorChannel: number, powerLevel: number): Promise { await this.sendCommand("setMotorConstantPower", { - id: this.id, - motorChannel: motorChannel, - motorPower: powerLevel, + hId: this.id, + c: motorChannel, + p: powerLevel, }); } @@ -531,9 +532,9 @@ export class ControlHubConnected implements ParentExpansionHub { pid: PidCoefficients, ): Promise { await this.sendCommand("setMotorPidCoefficients", { - id: this.id, - motorChannel: motorChannel, - motorMode: motorMode, + hId: this.id, + c: motorChannel, + m: motorMode, p: pid.p, i: pid.i, d: pid.d, @@ -546,8 +547,8 @@ export class ControlHubConnected implements ParentExpansionHub { targetTolerance_counts: number, ): Promise { await this.sendCommand("setMotorTargetPosition", { - id: this.id, - motorChannel: motorChannel, + hId: this.id, + c: motorChannel, targetPositionCounts: targetPosition_counts, targetToleranceCounts: targetTolerance_counts, }); @@ -558,22 +559,22 @@ export class ControlHubConnected implements ParentExpansionHub { velocity_cps: number, ): Promise { await this.sendCommand("setMotorTargetVelocity", { - id: this.id, - motorChannel: motorChannel, + hId: this.id, + c: motorChannel, velocityCps: velocity_cps, }); } async setNewModuleAddress(newModuleAddress: number): Promise { await this.sendCommand("setNewModuleAddress", { - id: this.id, + hId: this.id, address: newModuleAddress, }); } async setPhoneChargeControl(chargeEnable: boolean): Promise { await this.sendCommand("setPhoneChargeControl", { - id: this.id, + hId: this.id, enabled: chargeEnable, }); } @@ -583,24 +584,24 @@ export class ControlHubConnected implements ParentExpansionHub { framePeriod: number, ): Promise { await this.sendCommand("setServoConfiguration", { - id: this.id, - servoChannel: servoChannel, + hId: this.id, + c: servoChannel, framePeriod: framePeriod, }); } async setServoEnable(servoChannel: number, enable: boolean): Promise { await this.sendCommand("setServoEnable", { - id: this.id, - servoChannel: servoChannel, + hId: this.id, + c: servoChannel, enabled: enable, }); } async setServoPulseWidth(servoChannel: number, pulseWidth: number): Promise { await this.sendCommand("setServoPulseWidth", { - id: this.id, - servoChannel: servoChannel, + hId: this.id, + c: servoChannel, pulseWidth: pulseWidth, }); } diff --git a/packages/sample/package.json b/packages/sample/package.json index b5541866..8a2c0a12 100644 --- a/packages/sample/package.json +++ b/packages/sample/package.json @@ -3,7 +3,7 @@ "descripton": "sample for testing Rev Hub code", "version": "1.0.0", "main": "dist/main.js", - "bin": "revhub", + "bin": "dist/main.js", "private": true, "type": "module", "dependencies": { diff --git a/packages/sample/src/command/motor.ts b/packages/sample/src/command/motor.ts index 81ff1491..de8c7c39 100644 --- a/packages/sample/src/command/motor.ts +++ b/packages/sample/src/command/motor.ts @@ -1,10 +1,10 @@ -import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; -import { MotorMode } from "@rev-robotics/rev-hub-core"; - -export async function runMotorConstantPower(channel: number, power: number) { - const hubs = await openConnectedExpansionHubs(); - let hub = hubs[0]; +import { ExpansionHub, MotorMode } from "@rev-robotics/rev-hub-core"; +export async function runMotorConstantPower( + hub: ExpansionHub, + channel: number, + power: number, +) { await hub.setMotorChannelMode(channel, MotorMode.OPEN_LOOP, true); await hub.setMotorConstantPower(channel, power); await hub.setMotorChannelEnable(channel, true); @@ -15,10 +15,11 @@ export async function runMotorConstantPower(channel: number, power: number) { }); } -export async function runMotorConstantVelocity(channel: number, velocity: number) { - const hubs = await openConnectedExpansionHubs(); - let hub = hubs[0]; - +export async function runMotorConstantVelocity( + hub: ExpansionHub, + channel: number, + velocity: number, +) { await hub.setMotorChannelMode(channel, MotorMode.REGULATED_VELOCITY, true); await hub.setMotorTargetVelocity(channel, velocity); await hub.setMotorChannelEnable(channel, true); @@ -29,14 +30,12 @@ export async function runMotorConstantVelocity(channel: number, velocity: number } export async function runMotorToPosition( + hub: ExpansionHub, channel: number, velocity: number, position: number, tolerance: number, ) { - const hubs = await openConnectedExpansionHubs(); - let hub = hubs[0]; - await hub.setMotorChannelMode(channel, MotorMode.REGULATED_POSITION, true); await hub.setMotorTargetVelocity(channel, velocity); await hub.setMotorTargetPosition(channel, position, tolerance); @@ -47,10 +46,11 @@ export async function runMotorToPosition( }); } -export async function runEncoder(channel: number, continuous: boolean) { - const hubs = await openConnectedExpansionHubs(); - let hub = hubs[0]; - +export async function runEncoder( + hub: ExpansionHub, + channel: number, + continuous: boolean, +) { while (true) { let encoder = await hub.getMotorEncoderPosition(channel); console.log(`Encoder count is ${encoder}`); @@ -59,10 +59,7 @@ export async function runEncoder(channel: number, continuous: boolean) { hub.close(); } -export async function resetEncoder(channel: number) { - const hubs = await openConnectedExpansionHubs(); - let hub = hubs[0]; - +export async function resetEncoder(hub: ExpansionHub, channel: number) { await hub.resetMotorEncoder(channel); hub.close(); } diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 4cb1bd2a..f1c1c18e 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -124,11 +124,12 @@ motorCommand .description("Get the current encoder position of a motor") .action(async (channel, options) => { let channelNumber = Number(channel); + let hub = await getExpansionHubOrThrow(); if (options.reset) { - await resetEncoder(channelNumber); + await resetEncoder(hub, channelNumber); } else { let isContinuous = options.continuous !== undefined; - await runEncoder(channelNumber, isContinuous); + await runEncoder(hub, channelNumber, isContinuous); } }); @@ -141,7 +142,8 @@ motorCommand console.log(`${channel} ${power}`); let channelNumber = Number(channel); let powerNumber = Number(power); - await runMotorConstantPower(channelNumber, powerNumber); + let hub = await getExpansionHubOrThrow(); + await runMotorConstantPower(hub, channelNumber, powerNumber); }); motorCommand @@ -151,7 +153,8 @@ motorCommand console.log(`${channel} ${speed}`); let channelNumber = Number(channel); let speedNumber = Number(speed); - await runMotorConstantVelocity(channelNumber, speedNumber); + let hub = await getExpansionHubOrThrow(); + await runMotorConstantVelocity(hub, channelNumber, speedNumber); }); motorCommand @@ -163,7 +166,9 @@ motorCommand let positionNumber = Number(position); let toleranceNumber = Number(tolerance); let velocityNumber = Number(velocity); + let hub = await getExpansionHubOrThrow(); await runMotorToPosition( + hub, channelNumber, velocityNumber, positionNumber, From b3cf1d01df9b1396415d2d9e722ab13b6768b713 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 16 Jun 2023 16:30:23 -0500 Subject: [PATCH 097/148] setup rollup --- package-lock.json | 505 +++++++++++++++++- packages/control-hub/src/index.ts | 17 +- .../control-hub/src/internal/ControlHub.ts | 35 -- packages/control-hub/src/open-control-hub.ts | 12 + packages/core/src/RevHubError.ts | 2 +- packages/core/src/index.ts | 1 + .../src/nack-errors/BatteryTooLowError.ts | 3 +- .../src/nack-errors/GeneralSerialError.ts | 2 +- packages/core/src/nack-errors/NackError.ts | 6 +- .../NoExpansionHubWithAddressError.ts | 2 +- .../nack-errors/ParameterOutOfRangeError.ts | 3 +- packages/core/src/nack-errors/TimeoutError.ts | 2 +- .../src/nack-errors/UnrecognizedNackError.ts | 3 +- .../core/src/nack-errors/diagnostic-errors.ts | 3 +- .../src/nack-errors/digital-channel-errors.ts | 3 +- packages/core/src/nack-errors/i2c-errors.ts | 3 +- packages/core/src/nack-errors/motor-errors.ts | 3 +- packages/core/src/nack-errors/servo-errors.ts | 3 +- .../core/src/nack-errors/set-prototype.ts | 4 + packages/core/src/serial-errors.ts | 2 +- .../src/internal/ExpansionHub.ts | 3 +- packages/expansion-hub/src/open-rev-hub.ts | 63 +-- packages/expansion-hub/src/serial.ts | 67 +++ packages/rhsplib/lib/binding.ts | 4 +- packages/sample/package.json | 8 +- packages/sample/rollup.config.js | 33 ++ packages/sample/src/command/list.ts | 6 +- packages/sample/src/open-usb-control-hub.ts | 37 ++ 28 files changed, 698 insertions(+), 137 deletions(-) create mode 100644 packages/control-hub/src/open-control-hub.ts create mode 100644 packages/core/src/nack-errors/set-prototype.ts create mode 100644 packages/expansion-hub/src/serial.ts create mode 100644 packages/sample/rollup.config.js create mode 100644 packages/sample/src/open-usb-control-hub.ts diff --git a/package-lock.json b/package-lock.json index ed1f0fc1..af7aff37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -125,6 +125,12 @@ "dev": true, "license": "ISC" }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, "node_modules/@lerna/add": { "version": "6.0.1", "dev": true, @@ -1848,6 +1854,124 @@ "resolved": "packages/rhsplib", "link": true }, + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.1.tgz", + "integrity": "sha512-2DJ4kv4b1xfTJopWhu61ANdNRHvzQZ2fpaIrlgaP2jOfUv1wDJ0Ucqy8AZlbFmn/iUjiwKoqki9j55Y6L8kyNQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.27.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.0.0.tgz", + "integrity": "sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz", + "integrity": "sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.1.tgz", + "integrity": "sha512-Ioir+x5Bejv72Lx2Zbz3/qGg7tvGbxQZALCLoJaGrkNXak/19+vKgKYJYM3i/fJxvsb23I9FuFQ8CUBEfsmBRg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@serialport/binding-mock": { "version": "10.2.2", "license": "MIT", @@ -2018,6 +2142,12 @@ "@types/ms": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true + }, "node_modules/@types/long": { "version": "4.0.2", "license": "MIT" @@ -2059,6 +2189,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, "node_modules/@types/semver": { "version": "7.5.0", "dev": true, @@ -2475,6 +2611,18 @@ "dev": true, "license": "MIT" }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/builtins": { "version": "5.0.1", "dev": true, @@ -2733,6 +2881,12 @@ "dev": true, "license": "ISC" }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, "node_modules/compare-func": { "version": "2.0.0", "dev": true, @@ -3029,6 +3183,15 @@ "dev": true, "license": "MIT" }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/defaults": { "version": "1.0.4", "dev": true, @@ -3235,6 +3398,12 @@ "node": ">=4" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, "node_modules/eventemitter3": { "version": "4.0.7", "dev": true, @@ -3475,6 +3644,21 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "dev": true, @@ -4100,6 +4284,21 @@ "dev": true, "license": "MIT" }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-ci": { "version": "2.0.0", "dev": true, @@ -4176,6 +4375,12 @@ "dev": true, "license": "MIT" }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "node_modules/is-number": { "version": "7.0.0", "dev": true, @@ -4208,6 +4413,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/is-ssh": { "version": "1.4.0", "dev": true, @@ -4851,6 +5065,18 @@ "node": ">=12" } }, + "node_modules/magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/make-dir": { "version": "3.1.0", "dev": true, @@ -6839,6 +7065,68 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz", + "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==", + "dev": true, + "peer": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-exclude-dependencies-from-bundle": { + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/rollup-plugin-exclude-dependencies-from-bundle/-/rollup-plugin-exclude-dependencies-from-bundle-1.1.23.tgz", + "integrity": "sha512-nDoFtxlpajcqaLkPftoUcHxHYFd8tydHleOVubdf2JmyQtWTbhCNK05O4VGxLr7EUKSK9KeXqbWuQXkTqeJcRg==", + "dev": true, + "peerDependencies": { + "rollup": "*" + } + }, + "node_modules/rollup-plugin-natives": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/rollup-plugin-natives/-/rollup-plugin-natives-0.7.6.tgz", + "integrity": "sha512-G3jnCjZJgpOxOz4sYGwAYzemMhCQvb9mzhOrO5zTdNGkG5fiIcpETEURTD5BB+R6lC4j4BdWkHKf+FLofoymJw==", + "dev": true, + "dependencies": { + "fs-extra": "^10.1.0", + "magic-string": "^0.25.9" + }, + "peerDependencies": { + "rollup": ">=0.56.0" + } + }, + "node_modules/rollup-plugin-natives/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/rollup-plugin-natives/node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, "node_modules/run-async": { "version": "2.4.1", "dev": true, @@ -7063,6 +7351,13 @@ "node": ">=0.10.0" } }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true + }, "node_modules/spdx-correct": { "version": "3.2.0", "dev": true, @@ -7889,9 +8184,15 @@ "rev-hub-cli": "revhub" }, "devDependencies": { + "@rollup/plugin-commonjs": "^25.0.1", + "@rollup/plugin-json": "^6.0.0", + "@rollup/plugin-node-resolve": "^15.1.0", + "@rollup/plugin-typescript": "^11.1.1", "@types/debug": "^4.1.8", "@types/node-forge": "^1.3.2", - "@types/ws": "^8.5.4" + "@types/ws": "^8.5.4", + "rollup-plugin-exclude-dependencies-from-bundle": "^1.1.23", + "rollup-plugin-natives": "^0.7.6" } } }, @@ -7972,6 +8273,12 @@ "version": "1.1.0", "dev": true }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, "@lerna/add": { "version": "6.0.1", "dev": true, @@ -9247,6 +9554,64 @@ "typescript": "^5.0.2" } }, + "@rollup/plugin-commonjs": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.1.tgz", + "integrity": "sha512-2DJ4kv4b1xfTJopWhu61ANdNRHvzQZ2fpaIrlgaP2jOfUv1wDJ0Ucqy8AZlbFmn/iUjiwKoqki9j55Y6L8kyNQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.27.0" + } + }, + "@rollup/plugin-json": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.0.0.tgz", + "integrity": "sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1" + } + }, + "@rollup/plugin-node-resolve": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz", + "integrity": "sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + } + }, + "@rollup/plugin-typescript": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.1.tgz", + "integrity": "sha512-Ioir+x5Bejv72Lx2Zbz3/qGg7tvGbxQZALCLoJaGrkNXak/19+vKgKYJYM3i/fJxvsb23I9FuFQ8CUBEfsmBRg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "resolve": "^1.22.1" + } + }, + "@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + } + }, "@serialport/binding-mock": { "version": "10.2.2", "requires": { @@ -9323,6 +9688,12 @@ "@types/ms": "*" } }, + "@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true + }, "@types/long": { "version": "4.0.2" }, @@ -9356,6 +9727,12 @@ "version": "4.0.0", "dev": true }, + "@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, "@types/semver": { "version": "7.5.0", "dev": true @@ -9616,6 +9993,12 @@ "version": "1.1.2", "dev": true }, + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true + }, "builtins": { "version": "5.0.1", "dev": true, @@ -9781,6 +10164,12 @@ "version": "1.0.1", "dev": true }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, "compare-func": { "version": "2.0.0", "dev": true, @@ -9978,6 +10367,12 @@ "version": "0.7.0", "dev": true }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, "defaults": { "version": "1.0.4", "dev": true, @@ -10102,6 +10497,12 @@ "version": "4.0.1", "dev": true }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, "eventemitter3": { "version": "4.0.7", "dev": true @@ -10264,6 +10665,14 @@ "version": "1.0.0", "dev": true }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true, + "peer": true + }, "function-bind": { "version": "1.1.1", "dev": true @@ -10686,6 +11095,15 @@ "version": "0.2.1", "dev": true }, + "is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "requires": { + "builtin-modules": "^3.3.0" + } + }, "is-ci": { "version": "2.0.0", "dev": true, @@ -10727,6 +11145,12 @@ "version": "1.0.1", "dev": true }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "is-number": { "version": "7.0.0", "dev": true @@ -10743,6 +11167,15 @@ "version": "5.0.0", "dev": true }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, "is-ssh": { "version": "1.4.0", "dev": true, @@ -11175,6 +11608,15 @@ "version": "7.18.3", "dev": true }, + "magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + }, "make-dir": { "version": "3.1.0", "dev": true, @@ -12438,12 +12880,18 @@ "requires": { "@rev-robotics/control-hub": "1.0.0", "@rev-robotics/expansion-hub": "1.0.0", + "@rollup/plugin-commonjs": "^25.0.1", + "@rollup/plugin-json": "^6.0.0", + "@rollup/plugin-node-resolve": "^15.1.0", + "@rollup/plugin-typescript": "^11.1.1", "@types/debug": "^4.1.8", "@types/node-forge": "^1.3.2", "@types/ws": "^8.5.4", "@u4/adbkit": "^4.1.19", "commander": "^10.0.1", "get-port": "^6.1.2", + "rollup-plugin-exclude-dependencies-from-bundle": "^1.1.23", + "rollup-plugin-natives": "^0.7.6", "ws": "8.13.0" } }, @@ -12468,6 +12916,55 @@ } } }, + "rollup": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz", + "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==", + "dev": true, + "peer": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-exclude-dependencies-from-bundle": { + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/rollup-plugin-exclude-dependencies-from-bundle/-/rollup-plugin-exclude-dependencies-from-bundle-1.1.23.tgz", + "integrity": "sha512-nDoFtxlpajcqaLkPftoUcHxHYFd8tydHleOVubdf2JmyQtWTbhCNK05O4VGxLr7EUKSK9KeXqbWuQXkTqeJcRg==", + "dev": true, + "requires": {} + }, + "rollup-plugin-natives": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/rollup-plugin-natives/-/rollup-plugin-natives-0.7.6.tgz", + "integrity": "sha512-G3jnCjZJgpOxOz4sYGwAYzemMhCQvb9mzhOrO5zTdNGkG5fiIcpETEURTD5BB+R6lC4j4BdWkHKf+FLofoymJw==", + "dev": true, + "requires": { + "fs-extra": "^10.1.0", + "magic-string": "^0.25.9" + }, + "dependencies": { + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.8" + } + } + } + }, "run-async": { "version": "2.4.1", "dev": true @@ -12595,6 +13092,12 @@ "version": "0.6.1", "dev": true }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, "spdx-correct": { "version": "3.2.0", "dev": true, diff --git a/packages/control-hub/src/index.ts b/packages/control-hub/src/index.ts index 3ac46878..7dca452d 100644 --- a/packages/control-hub/src/index.ts +++ b/packages/control-hub/src/index.ts @@ -1,15 +1,2 @@ -import { ControlHubInternal } from "./internal/ControlHub.js"; -import { ControlHub } from "@rev-robotics/rev-hub-core"; - -export { openConnectedControlHub } from "./discovery.js"; -export { openUsbControlHubsAndChildren } from "./internal/ControlHub.js"; - -export async function openControlHub( - serialNumber: string, - moduleAddress: number, - port: number, -): Promise { - let hub = new ControlHubInternal(serialNumber); - await hub.open("127.0.0.1", (port + 1).toString()); - return hub; -} +export * from "./open-control-hub.js"; +export * from "./discovery.js"; diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index e9b64152..2413c17e 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -24,7 +24,6 @@ import { VerbosityLevel, Version, } from "@rev-robotics/rev-hub-core"; -import { openUsbControlHubs } from "rev-hub-cli/dist/adb-setup.js"; import { clearTimeout } from "timers"; import { ControlHubConnected } from "./ControlHubConnected.js"; @@ -623,37 +622,3 @@ export class ControlHubInternal implements ControlHub { }); } } - -export async function openUsbControlHubsAndChildren(): Promise { - let hubs = await openUsbControlHubs(); - let result: ControlHub[] = []; - - for (let hub of hubs) { - let controlHub = hub as ControlHubInternal; - let addresses: Record< - string, - { - serialNumber: string; - parentHubAddress: number; - childAddresses: number[]; - } - > = await controlHub.sendCommand("scanAndDiscover", {}, 20000); - - for (let serialNumber in addresses) { - if (serialNumber === "(embedded)") continue; - - let parentHubInfo = addresses[serialNumber]; - let parentHub = await controlHub.addHubBySerialNumberAndAddress( - serialNumber, - parentHubInfo.parentHubAddress, - ); - - for (let childAddress of parentHubInfo.childAddresses) { - await parentHub.addChildByAddress(childAddress); - } - } - result.push(controlHub); - } - - return result; -} diff --git a/packages/control-hub/src/open-control-hub.ts b/packages/control-hub/src/open-control-hub.ts new file mode 100644 index 00000000..53271e43 --- /dev/null +++ b/packages/control-hub/src/open-control-hub.ts @@ -0,0 +1,12 @@ +import { ControlHub } from "@rev-robotics/rev-hub-core"; +import { ControlHubInternal } from "./internal/ControlHub.js"; + +export async function openControlHub( + serialNumber: string, + moduleAddress: number, + port: number, +): Promise { + let hub = new ControlHubInternal(serialNumber); + await hub.open("127.0.0.1", (port + 1).toString()); + return hub; +} diff --git a/packages/core/src/RevHubError.ts b/packages/core/src/RevHubError.ts index 936a1d5a..67438ffe 100644 --- a/packages/core/src/RevHubError.ts +++ b/packages/core/src/RevHubError.ts @@ -1,4 +1,4 @@ -import { setPrototypeOf } from "./nack-errors/NackError.js"; +import { setPrototypeOf } from "./nack-errors/set-prototype.js"; export class RevHubError extends Error { constructor(message: string) { diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 3fdd1efc..2b50cb96 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -22,6 +22,7 @@ export * from "./SerialParity.js"; export * from "./VerbosityLevel.js"; export * from "./Version.js"; export * from "./serial-errors.js"; +export * from "./nack-errors/set-prototype.js"; export * from "./nack-errors/nack-codes.js"; export * from "./nack-errors/NackError.js"; export * from "./nack-errors/BatteryTooLowError.js"; diff --git a/packages/core/src/nack-errors/BatteryTooLowError.ts b/packages/core/src/nack-errors/BatteryTooLowError.ts index fb9b3a80..3ebbb452 100644 --- a/packages/core/src/nack-errors/BatteryTooLowError.ts +++ b/packages/core/src/nack-errors/BatteryTooLowError.ts @@ -1,4 +1,5 @@ -import {NackError, setPrototypeOf} from "./NackError.js"; +import { NackError } from "./NackError.js"; +import { setPrototypeOf } from "./set-prototype.js"; export class BatteryTooLowError extends NackError { constructor(nackCode: number, message: string) { diff --git a/packages/core/src/nack-errors/GeneralSerialError.ts b/packages/core/src/nack-errors/GeneralSerialError.ts index 5910c1cb..6a4870f6 100644 --- a/packages/core/src/nack-errors/GeneralSerialError.ts +++ b/packages/core/src/nack-errors/GeneralSerialError.ts @@ -1,4 +1,4 @@ -import { setPrototypeOf } from "./NackError.js"; +import { setPrototypeOf } from "./set-prototype.js"; /** * Indicates an error in the Serial connection. diff --git a/packages/core/src/nack-errors/NackError.ts b/packages/core/src/nack-errors/NackError.ts index 1f36f159..098c6326 100644 --- a/packages/core/src/nack-errors/NackError.ts +++ b/packages/core/src/nack-errors/NackError.ts @@ -15,11 +15,7 @@ Modified to use Object.setPrototypeOf instead of __proto__ and to be a global function */ import { RevHubError } from "../RevHubError.js"; - -export function setPrototypeOf(obj: any, proto: any) { - Object.setPrototypeOf(obj, proto); - return obj; -} +import { setPrototypeOf } from "./set-prototype.js"; export class NackError extends RevHubError { nackCode: number; diff --git a/packages/core/src/nack-errors/NoExpansionHubWithAddressError.ts b/packages/core/src/nack-errors/NoExpansionHubWithAddressError.ts index 111013fd..12341830 100644 --- a/packages/core/src/nack-errors/NoExpansionHubWithAddressError.ts +++ b/packages/core/src/nack-errors/NoExpansionHubWithAddressError.ts @@ -1,4 +1,4 @@ -import { setPrototypeOf } from "./NackError.js"; +import { setPrototypeOf } from "./set-prototype.js"; export class NoExpansionHubWithAddressError extends Error { moduleAddress: number; diff --git a/packages/core/src/nack-errors/ParameterOutOfRangeError.ts b/packages/core/src/nack-errors/ParameterOutOfRangeError.ts index 324af1c4..ba9c7ca4 100644 --- a/packages/core/src/nack-errors/ParameterOutOfRangeError.ts +++ b/packages/core/src/nack-errors/ParameterOutOfRangeError.ts @@ -1,4 +1,5 @@ -import { NackError, setPrototypeOf } from "./NackError.js"; +import { setPrototypeOf } from "./set-prototype.js"; +import { NackError } from "./NackError.js"; export class ParameterOutOfRangeError extends NackError { /** diff --git a/packages/core/src/nack-errors/TimeoutError.ts b/packages/core/src/nack-errors/TimeoutError.ts index 7d42caa6..5b8779ca 100644 --- a/packages/core/src/nack-errors/TimeoutError.ts +++ b/packages/core/src/nack-errors/TimeoutError.ts @@ -1,4 +1,4 @@ -import { setPrototypeOf } from "./NackError.js"; +import { setPrototypeOf } from "./set-prototype.js"; export class TimeoutError extends Error { constructor() { diff --git a/packages/core/src/nack-errors/UnrecognizedNackError.ts b/packages/core/src/nack-errors/UnrecognizedNackError.ts index bf0233b0..b0985c31 100644 --- a/packages/core/src/nack-errors/UnrecognizedNackError.ts +++ b/packages/core/src/nack-errors/UnrecognizedNackError.ts @@ -1,4 +1,5 @@ -import { NackError, setPrototypeOf } from "./NackError.js"; +import { setPrototypeOf } from "./set-prototype.js"; +import { NackError } from "./NackError.js"; export class UnrecognizedNackError extends NackError { constructor(nackCode: number) { diff --git a/packages/core/src/nack-errors/diagnostic-errors.ts b/packages/core/src/nack-errors/diagnostic-errors.ts index fb22c32e..e9e67bdf 100644 --- a/packages/core/src/nack-errors/diagnostic-errors.ts +++ b/packages/core/src/nack-errors/diagnostic-errors.ts @@ -1,5 +1,6 @@ -import { NackError, setPrototypeOf } from "./NackError.js"; +import { NackError } from "./NackError.js"; import { NackCode } from "./nack-codes.js"; +import { setPrototypeOf } from "./set-prototype.js"; export class CommandImplementationPendingError extends NackError { constructor() { diff --git a/packages/core/src/nack-errors/digital-channel-errors.ts b/packages/core/src/nack-errors/digital-channel-errors.ts index dafa459a..f9adc116 100644 --- a/packages/core/src/nack-errors/digital-channel-errors.ts +++ b/packages/core/src/nack-errors/digital-channel-errors.ts @@ -1,4 +1,5 @@ -import { NackError, setPrototypeOf } from "./NackError.js"; +import { setPrototypeOf } from "./set-prototype.js"; +import { NackError } from "./NackError.js"; import { NackCode } from "./nack-codes.js"; export class DigitalChannelNotConfiguredForOutputError extends NackError { diff --git a/packages/core/src/nack-errors/i2c-errors.ts b/packages/core/src/nack-errors/i2c-errors.ts index 42d6b110..45b0845a 100644 --- a/packages/core/src/nack-errors/i2c-errors.ts +++ b/packages/core/src/nack-errors/i2c-errors.ts @@ -1,4 +1,5 @@ -import { NackError, setPrototypeOf } from "./NackError.js"; +import { setPrototypeOf } from "./set-prototype.js"; +import { NackError } from "./NackError.js"; import { NackCode } from "./nack-codes.js"; export class I2cControllerBusyError extends NackError { diff --git a/packages/core/src/nack-errors/motor-errors.ts b/packages/core/src/nack-errors/motor-errors.ts index df5e341f..87285c15 100644 --- a/packages/core/src/nack-errors/motor-errors.ts +++ b/packages/core/src/nack-errors/motor-errors.ts @@ -1,4 +1,5 @@ -import { NackError, setPrototypeOf } from "./NackError.js"; +import { setPrototypeOf } from "./set-prototype.js"; +import { NackError } from "./NackError.js"; import { BatteryTooLowError } from "./BatteryTooLowError.js"; import { NackCode } from "./nack-codes.js"; diff --git a/packages/core/src/nack-errors/servo-errors.ts b/packages/core/src/nack-errors/servo-errors.ts index 49c61925..75bb5f54 100644 --- a/packages/core/src/nack-errors/servo-errors.ts +++ b/packages/core/src/nack-errors/servo-errors.ts @@ -1,4 +1,5 @@ -import { NackError, setPrototypeOf } from "./NackError.js"; +import { setPrototypeOf } from "./set-prototype.js"; +import { NackError } from "./NackError.js"; import { BatteryTooLowError } from "./BatteryTooLowError.js"; import { NackCode } from "./nack-codes.js"; diff --git a/packages/core/src/nack-errors/set-prototype.ts b/packages/core/src/nack-errors/set-prototype.ts new file mode 100644 index 00000000..0995d06a --- /dev/null +++ b/packages/core/src/nack-errors/set-prototype.ts @@ -0,0 +1,4 @@ +export function setPrototypeOf(obj: any, proto: any) { + Object.setPrototypeOf(obj, proto); + return obj; +} diff --git a/packages/core/src/serial-errors.ts b/packages/core/src/serial-errors.ts index f56fe3c9..0e0948d9 100644 --- a/packages/core/src/serial-errors.ts +++ b/packages/core/src/serial-errors.ts @@ -1,4 +1,4 @@ -import { setPrototypeOf } from "./nack-errors/NackError.js"; +import { setPrototypeOf } from "./nack-errors/set-prototype.js"; export class UnableToOpenSerialError extends Error { constructor(serialPort: string) { diff --git a/packages/expansion-hub/src/internal/ExpansionHub.ts b/packages/expansion-hub/src/internal/ExpansionHub.ts index 3eb0fd09..d443d0fb 100644 --- a/packages/expansion-hub/src/internal/ExpansionHub.ts +++ b/packages/expansion-hub/src/internal/ExpansionHub.ts @@ -1,5 +1,4 @@ import { - DigitalChannelDirection, DigitalState, ExpansionHub, ParentRevHub, @@ -33,7 +32,7 @@ import { CommandNotSupportedError, I2cOperationInProgressError, } from "@rev-robotics/rev-hub-core"; -import { closeSerialPort } from "../open-rev-hub.js"; +import { closeSerialPort } from "../serial.js"; import { EventEmitter } from "events"; import { RevHubType, MotorMode } from "@rev-robotics/rev-hub-core"; import { RhspLibError } from "../errors/RhspLibError.js"; diff --git a/packages/expansion-hub/src/open-rev-hub.ts b/packages/expansion-hub/src/open-rev-hub.ts index 08748f5e..6469caf3 100644 --- a/packages/expansion-hub/src/open-rev-hub.ts +++ b/packages/expansion-hub/src/open-rev-hub.ts @@ -22,13 +22,7 @@ import { SerialPort as SerialLister } from "serialport"; import { ExpansionHubInternal } from "./internal/ExpansionHub.js"; import { startKeepAlive } from "./start-keep-alive.js"; import { performance } from "perf_hooks"; - -/** - * Maps the serial port path (/dev/tty1 or COM3 for example) to an open - * Serial object at that path. The {@link SerialPort} object should be removed from - * the map upon closing. - */ -const openSerialMap = new Map(); +import { getSerial } from "./serial.js"; /** * @@ -65,11 +59,7 @@ export async function openParentExpansionHub( ): Promise { let serialPortPath = await getSerialPortPathForExHubSerial(serialNumber); - if (openSerialMap.get(serialPortPath) == undefined) { - openSerialMap.set(serialPortPath, await openSerialPort(serialPortPath)); - } - - let serialPort = openSerialMap.get(serialPortPath)!; + let serialPort = await getSerial(serialPortPath); let parentHub = new ExpansionHubInternal(true, serialPort, serialNumber); @@ -121,11 +111,7 @@ export async function openExpansionHubAndAllChildren( ): Promise { let serialPortPath = await getSerialPortPathForExHubSerial(serialNumber); - if (openSerialMap.get(serialPortPath) == undefined) { - openSerialMap.set(serialPortPath, await openSerialPort(serialPortPath)); - } - - let serialPort = openSerialMap.get(serialPortPath)!; + let serialPort = await getSerial(serialPortPath); let discoveredModules = await NativeRevHub.discoverRevHubs(serialPort); let parentAddress = discoveredModules.parentAddress; @@ -154,46 +140,3 @@ async function getSerialPortPathForExHubSerial(serialNumber: string): Promise { - let serial = new NativeSerial(); - try { - await serial.open( - serialPortPath, - 460800, - 8, - SerialParity.None, - 1, - SerialFlowControl.None, - ); - } catch (e: any) { - let code = e.errorCode; - if (code == SerialError.INVALID_ARGS) { - throw new InvalidSerialArguments(serialPortPath); - } else if (code == SerialError.UNABLE_TO_OPEN) { - throw new UnableToOpenSerialError(serialPortPath); - } else if (code == SerialError.CONFIGURATION_ERROR) { - throw new SerialConfigurationError(serialPortPath); - } else if (code == SerialError.IO_ERROR) { - throw new SerialIoError(serialPortPath); - } else if (code == SerialError.GENERAL_ERROR) { - throw new GeneralSerialError(serialPortPath); - } - } - return serial; -} diff --git a/packages/expansion-hub/src/serial.ts b/packages/expansion-hub/src/serial.ts new file mode 100644 index 00000000..7e412391 --- /dev/null +++ b/packages/expansion-hub/src/serial.ts @@ -0,0 +1,67 @@ +import { NativeSerial, SerialError, SerialFlowControl } from "@rev-robotics/rhsplib"; +import { + GeneralSerialError, + InvalidSerialArguments, + SerialConfigurationError, + SerialIoError, + SerialParity, + UnableToOpenSerialError, +} from "@rev-robotics/rev-hub-core"; + +/** + * Maps the serial port path (/dev/tty1 or COM3 for example) to an open + * Serial object at that path. The {@link NativeSerial} object should be removed from + * the map upon closing. + */ +const openSerialMap = new Map(); + +/** + * Closes the given Serial port and removes it from the open serial ports + * list. This should be the preferred way to close a Serial port. + * + * @param serialPort the Serial port to close + */ +export function closeSerialPort(serialPort: typeof NativeSerial) { + for (let [path, port] of openSerialMap.entries()) { + if (port === serialPort) { + openSerialMap.delete(path); + } + } + serialPort.close(); +} + +export async function getSerial(serialPortPath: string): Promise { + if (openSerialMap.get(serialPortPath) == undefined) { + openSerialMap.set(serialPortPath, await openSerialPort(serialPortPath)); + } + + return openSerialMap.get(serialPortPath); +} + +async function openSerialPort(serialPortPath: string): Promise { + let serial = new NativeSerial(); + try { + await serial.open( + serialPortPath, + 460800, + 8, + SerialParity.None, + 1, + SerialFlowControl.None, + ); + } catch (e: any) { + let code = e.errorCode; + if (code == SerialError.INVALID_ARGS) { + throw new InvalidSerialArguments(serialPortPath); + } else if (code == SerialError.UNABLE_TO_OPEN) { + throw new UnableToOpenSerialError(serialPortPath); + } else if (code == SerialError.CONFIGURATION_ERROR) { + throw new SerialConfigurationError(serialPortPath); + } else if (code == SerialError.IO_ERROR) { + throw new SerialIoError(serialPortPath); + } else if (code == SerialError.GENERAL_ERROR) { + throw new GeneralSerialError(serialPortPath); + } + } + return serial; +} diff --git a/packages/rhsplib/lib/binding.ts b/packages/rhsplib/lib/binding.ts index 5d6a08fd..7f836977 100644 --- a/packages/rhsplib/lib/binding.ts +++ b/packages/rhsplib/lib/binding.ts @@ -24,7 +24,9 @@ import { SerialParity } from "@rev-robotics/rev-hub-core"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const require = createRequire(import.meta.url); -const addon = require("node-gyp-build")(path.join(__dirname, "..")); +console.log(`Directory: ${__dirname}`); +const nodeBuild = require("node-gyp-build"); +const addon = nodeBuild(path.join(__dirname, "..")); export * from "./error-codes.js"; export * from "./serial-errors.js"; diff --git a/packages/sample/package.json b/packages/sample/package.json index 8a2c0a12..a46ff304 100644 --- a/packages/sample/package.json +++ b/packages/sample/package.json @@ -3,7 +3,7 @@ "descripton": "sample for testing Rev Hub code", "version": "1.0.0", "main": "dist/main.js", - "bin": "dist/main.js", + "bin": "revhub", "private": true, "type": "module", "dependencies": { @@ -17,6 +17,12 @@ "devDependencies": { "@types/ws": "^8.5.4", "@types/node-forge": "^1.3.2", + "@rollup/plugin-node-resolve": "^15.1.0", + "@rollup/plugin-typescript": "^11.1.1", + "@rollup/plugin-commonjs": "^25.0.1", + "rollup-plugin-exclude-dependencies-from-bundle": "^1.1.23", + "@rollup/plugin-json": "^6.0.0", + "rollup-plugin-natives": "^0.7.6", "@types/debug": "^4.1.8" }, "scripts": { diff --git a/packages/sample/rollup.config.js b/packages/sample/rollup.config.js new file mode 100644 index 00000000..b8adfb68 --- /dev/null +++ b/packages/sample/rollup.config.js @@ -0,0 +1,33 @@ +import excludeDependenciesFromBundle from "rollup-plugin-exclude-dependencies-from-bundle"; +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; +import json from "@rollup/plugin-json"; +import addon from "rollup-plugin-natives"; + +import pkg from "./package.json" assert { type: "json" }; + +const PACKAGE_NAME = process.cwd(); + +const extensions = [".js", ".ts", ".tsx"]; +const nodeOptions = { + extensions, +}; +const commonjsOptions = { + ignoreGlobal: true, + ignoreDynamicRequires: true, + include: /node_modules/, +}; + +export default { + input: `${PACKAGE_NAME}/dist/main.js`, + output: [ + { + file: "dist/output.js", + format: "cjs", + }, + ], + plugins: [nodeResolve(nodeOptions), commonjs(commonjsOptions), json()], + external: { + dependencies: pkg.dependencies, + }, +}; diff --git a/packages/sample/src/command/list.ts b/packages/sample/src/command/list.ts index 5de9a8a7..dccd5a51 100644 --- a/packages/sample/src/command/list.ts +++ b/packages/sample/src/command/list.ts @@ -1,10 +1,8 @@ import { openConnectedExpansionHubs } from "@rev-robotics/expansion-hub"; import { controlHubHierarchyToString } from "../HubStringify.js"; -import { - openConnectedControlHub, - openUsbControlHubsAndChildren, -} from "@rev-robotics/control-hub"; import { ExpansionHub } from "@rev-robotics/rev-hub-core"; +import { openUsbControlHubsAndChildren } from "../open-usb-control-hub.js"; +import { openConnectedControlHub } from "@rev-robotics/control-hub"; export async function list() { let usbControlHubs = await openUsbControlHubsAndChildren(); diff --git a/packages/sample/src/open-usb-control-hub.ts b/packages/sample/src/open-usb-control-hub.ts new file mode 100644 index 00000000..f5ee3116 --- /dev/null +++ b/packages/sample/src/open-usb-control-hub.ts @@ -0,0 +1,37 @@ +import { ControlHub } from "@rev-robotics/rev-hub-core"; +import { ControlHubInternal } from "@rev-robotics/control-hub/dist/internal/ControlHub.js"; +import { openUsbControlHubs } from "./adb-setup.js"; + +export async function openUsbControlHubsAndChildren(): Promise { + let hubs = await openUsbControlHubs(); + let result: ControlHub[] = []; + + for (let hub of hubs) { + let controlHub = hub as ControlHubInternal; + let addresses: Record< + string, + { + serialNumber: string; + parentHubAddress: number; + childAddresses: number[]; + } + > = await controlHub.sendCommand("scanAndDiscover", {}, 20000); + + for (let serialNumber in addresses) { + if (serialNumber === "(embedded)") continue; + + let parentHubInfo = addresses[serialNumber]; + let parentHub = await controlHub.addHubBySerialNumberAndAddress( + serialNumber, + parentHubInfo.parentHubAddress, + ); + + for (let childAddress of parentHubInfo.childAddresses) { + await parentHub.addChildByAddress(childAddress); + } + } + result.push(controlHub); + } + + return result; +} From 30f69c252f01b24e16f7487a6ccf478bcc6424c1 Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 16 Jun 2023 16:48:13 -0500 Subject: [PATCH 098/148] remove node-addon issues --- control-hub-cli.bat | 2 ++ packages/rhsplib/lib/binding.ts | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) create mode 100644 control-hub-cli.bat diff --git a/control-hub-cli.bat b/control-hub-cli.bat new file mode 100644 index 00000000..538193a6 --- /dev/null +++ b/control-hub-cli.bat @@ -0,0 +1,2 @@ + +node.exe output.js %* \ No newline at end of file diff --git a/packages/rhsplib/lib/binding.ts b/packages/rhsplib/lib/binding.ts index 7f836977..d7827166 100644 --- a/packages/rhsplib/lib/binding.ts +++ b/packages/rhsplib/lib/binding.ts @@ -21,12 +21,7 @@ import { } from "@rev-robotics/rev-hub-core"; import { SerialParity } from "@rev-robotics/rev-hub-core"; -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -const require = createRequire(import.meta.url); -console.log(`Directory: ${__dirname}`); -const nodeBuild = require("node-gyp-build"); -const addon = nodeBuild(path.join(__dirname, "..")); +const addon: any = {}; export * from "./error-codes.js"; export * from "./serial-errors.js"; From 1477ba3e48af7113fecc9cfd6f70ba10ea86dd2d Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Fri, 16 Jun 2023 16:49:47 -0500 Subject: [PATCH 099/148] always use control hub --- packages/sample/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index f1c1c18e..f971a2f0 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -261,7 +261,7 @@ program.parse(process.argv); async function getExpansionHubOrThrow(): Promise { let options = program.opts(); let serialNumber = options.serial; - let isControlHub = options.control !== undefined; + let isControlHub = true; let moduleAddress = options.address ? Number(options.address) : undefined; let parentAddress = options.parent ? Number(options.parent) : undefined; From 91884112393e3b81162cd059149223cfafc41971 Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 18:09:32 -0500 Subject: [PATCH 100/148] Only allow Control Hub and its RS-485 children for demo purposes --- packages/sample/src/main.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index f971a2f0..ab135028 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -32,12 +32,12 @@ const program = new Command(); program.version("1.0.0"); program - .option("--control", "specify that you are connecting via control hub") - .option("-s --serial ", "serial number") - .option("-p --parent
", "parent address") + // .option("--control", "specify that you are connecting via control hub") + // .option("-s --serial ", "serial number") + // .option("-p --parent
", "parent address") .option( "-a --address
", - "module address. If this is specified, you must also specify a parent address", + "address of Expansion Hub connected via RS-485", ); program From 0caca2a7b6f953e700d01a3486031328b4a1757c Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 19:03:32 -0500 Subject: [PATCH 101/148] Update some field and command names --- .../src/internal/ControlHubConnected.ts | 106 +++++++++--------- 1 file changed, 51 insertions(+), 55 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHubConnected.ts b/packages/control-hub/src/internal/ControlHubConnected.ts index e44f871e..f741641d 100644 --- a/packages/control-hub/src/internal/ControlHubConnected.ts +++ b/packages/control-hub/src/internal/ControlHubConnected.ts @@ -59,7 +59,7 @@ export class ControlHubConnected implements ParentExpansionHub { async getAnalogInput(channel: number): Promise { return await this.sendCommand("getAnalogInput", { hId: this.id, - analogChannel: channel, + c: channel, }); } @@ -88,7 +88,7 @@ export class ControlHubConnected implements ParentExpansionHub { } async getI2CCurrent(): Promise { - return await this.sendCommand("getI2CCurrent", { + return await this.sendCommand("getI2cCurrent", { hId: this.id, }); } @@ -127,7 +127,7 @@ export class ControlHubConnected implements ParentExpansionHub { async getDigitalDirection(dioPin: number): Promise { let isOutput = await this.sendCommand("getDigitalDirection", { hId: this.id, - digitalChannel: dioPin, + c: dioPin, }); return isOutput ? DioDirection.Output : DioDirection.Input; @@ -136,7 +136,7 @@ export class ControlHubConnected implements ParentExpansionHub { async getDigitalInput(dioPin: number): Promise { let result: boolean = await this.sendCommand("getDigitalInput", { hId: this.id, - digitalChannel: dioPin, + c: dioPin, }); return result ? DigitalState.High : DigitalState.Low; @@ -149,9 +149,9 @@ export class ControlHubConnected implements ParentExpansionHub { } async getI2CChannelConfiguration(i2cChannel: number): Promise { - let speedCode = await this.sendCommand("getI2CChannelConfiguration", { + let speedCode = await this.sendCommand("getI2cChannelConfiguration", { hId: this.id, - channel: i2cChannel, + c: i2cChannel, }); return speedCode == 1 @@ -182,8 +182,7 @@ export class ControlHubConnected implements ParentExpansionHub { let result: { r: number; g: number; b: number } = await this.sendCommand( "getLedColor", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + hId: this.id, }, ); @@ -254,8 +253,7 @@ export class ControlHubConnected implements ParentExpansionHub { let result: { p: number; i: number; d: number } = await this.sendCommand( "getMotorPidCoefficients", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + hId: this.id, c: motorChannel, m: motorMode, }, @@ -271,16 +269,15 @@ export class ControlHubConnected implements ParentExpansionHub { async getMotorTargetPosition( motorChannel: number, ): Promise<{ targetPosition: number; targetTolerance: number }> { - let result: { targetPositionCounts: number; targetToleranceCounts: number } = + let result: { tpc: number; ttc: number } = await this.sendCommand("getMotorTargetPosition", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + hId: this.id, c: motorChannel, }); return { - targetPosition: result.targetPositionCounts, - targetTolerance: result.targetToleranceCounts, + targetPosition: result.tpc, + targetTolerance: result.ttc, }; } @@ -336,8 +333,7 @@ export class ControlHubConnected implements ParentExpansionHub { async queryInterface(interfaceName: string): Promise { let result: { name: string; firstPacketId: number; numberIds: number } = await this.sendCommand("queryInterface", { - serialNumber: this.serialNumber, - moduleAddress: this.moduleAddress, + hId: this.id, interfaceName: interfaceName, }); @@ -376,7 +372,7 @@ export class ControlHubConnected implements ParentExpansionHub { } async readVersionString(): Promise { - return await this.sendCommand("readVersionString", { + return await this.sendCommand("getHubFwVersionString", { hId: this.id, }); } @@ -389,7 +385,7 @@ export class ControlHubConnected implements ParentExpansionHub { } async sendFailSafe(): Promise { - await this.sendCommand("readVersionString", { + await this.sendCommand("sendFailSafe", { hId: this.id, }); } @@ -408,7 +404,7 @@ export class ControlHubConnected implements ParentExpansionHub { debugGroup: DebugGroup, verbosityLevel: VerbosityLevel, ): Promise { - await this.sendCommand("readVersionString", { + await this.sendCommand("setDebugLogLevel", { hId: this.id, debugGroup: debugGroup, verbosityLevel: verbosityLevel, @@ -416,25 +412,25 @@ export class ControlHubConnected implements ParentExpansionHub { } async setAllDigitalOutputs(bitPackedField: number): Promise { - await this.sendCommand("readVersionString", { + await this.sendCommand("setAllDigitalOutputs", { hId: this.id, - bitField: bitPackedField, + bf: bitPackedField, }); } async setDigitalDirection(dioPin: number, direction: DioDirection): Promise { - await this.sendCommand("readVersionString", { + await this.sendCommand("setDigitalDirection", { hId: this.id, - pin: dioPin, - isOutput: direction == DioDirection.Output, + c: dioPin, + o: direction == DioDirection.Output, }); } async setDigitalOutput(dioPin: number, value: DigitalState): Promise { - await this.sendCommand("readVersionString", { + await this.sendCommand("setDigitalOutput", { hId: this.id, - digitalChannel: dioPin, - value: value.isHigh(), + c: dioPin, + v: value.isHigh(), }); } @@ -448,10 +444,10 @@ export class ControlHubConnected implements ParentExpansionHub { i2cChannel: number, speedCode: I2CSpeedCode, ): Promise { - await this.sendCommand("setI2CChannelConfiguration", { + await this.sendCommand("setI2cChannelConfiguration", { hId: this.id, - i2cChannel: i2cChannel, - speedCode: speedCode, + c: i2cChannel, + sc: speedCode, }); } @@ -467,22 +463,22 @@ export class ControlHubConnected implements ParentExpansionHub { async setModuleLedPattern(ledPattern: LedPattern): Promise { await this.sendCommand("setLedPattern", { hId: this.id, - rgbtPatternStep0: ledPattern.rgbtPatternStep0, - rgbtPatternStep1: ledPattern.rgbtPatternStep1, - rgbtPatternStep2: ledPattern.rgbtPatternStep2, - rgbtPatternStep3: ledPattern.rgbtPatternStep3, - rgbtPatternStep4: ledPattern.rgbtPatternStep4, - rgbtPatternStep5: ledPattern.rgbtPatternStep5, - rgbtPatternStep6: ledPattern.rgbtPatternStep6, - rgbtPatternStep7: ledPattern.rgbtPatternStep7, - rgbtPatternStep8: ledPattern.rgbtPatternStep8, - rgbtPatternStep9: ledPattern.rgbtPatternStep9, - rgbtPatternStep10: ledPattern.rgbtPatternStep10, - rgbtPatternStep11: ledPattern.rgbtPatternStep11, - rgbtPatternStep12: ledPattern.rgbtPatternStep12, - rgbtPatternStep13: ledPattern.rgbtPatternStep13, - rgbtPatternStep14: ledPattern.rgbtPatternStep14, - rgbtPatternStep15: ledPattern.rgbtPatternStep15, + s0: ledPattern.rgbtPatternStep0, + s1: ledPattern.rgbtPatternStep1, + s2: ledPattern.rgbtPatternStep2, + s3: ledPattern.rgbtPatternStep3, + s4: ledPattern.rgbtPatternStep4, + s5: ledPattern.rgbtPatternStep5, + s6: ledPattern.rgbtPatternStep6, + s7: ledPattern.rgbtPatternStep7, + s8: ledPattern.rgbtPatternStep8, + s9: ledPattern.rgbtPatternStep9, + s10: ledPattern.rgbtPatternStep10, + s11: ledPattern.rgbtPatternStep11, + s12: ledPattern.rgbtPatternStep12, + s13: ledPattern.rgbtPatternStep13, + s14: ledPattern.rgbtPatternStep14, + s15: ledPattern.rgbtPatternStep15, }); } @@ -549,8 +545,8 @@ export class ControlHubConnected implements ParentExpansionHub { await this.sendCommand("setMotorTargetPosition", { hId: this.id, c: motorChannel, - targetPositionCounts: targetPosition_counts, - targetToleranceCounts: targetTolerance_counts, + tpc: targetPosition_counts, + ttc: targetTolerance_counts, }); } @@ -561,14 +557,14 @@ export class ControlHubConnected implements ParentExpansionHub { await this.sendCommand("setMotorTargetVelocity", { hId: this.id, c: motorChannel, - velocityCps: velocity_cps, + tv: velocity_cps, }); } async setNewModuleAddress(newModuleAddress: number): Promise { - await this.sendCommand("setNewModuleAddress", { + await this.sendCommand("setHubAddress", { hId: this.id, - address: newModuleAddress, + newAddress: newModuleAddress, }); } @@ -586,7 +582,7 @@ export class ControlHubConnected implements ParentExpansionHub { await this.sendCommand("setServoConfiguration", { hId: this.id, c: servoChannel, - framePeriod: framePeriod, + fp: framePeriod, }); } @@ -594,7 +590,7 @@ export class ControlHubConnected implements ParentExpansionHub { await this.sendCommand("setServoEnable", { hId: this.id, c: servoChannel, - enabled: enable, + enable: enable, }); } @@ -602,7 +598,7 @@ export class ControlHubConnected implements ParentExpansionHub { await this.sendCommand("setServoPulseWidth", { hId: this.id, c: servoChannel, - pulseWidth: pulseWidth, + pw: pulseWidth, }); } From 2e8178c829cfdbff1e1f0649575c97af10f6b93d Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 19:24:08 -0500 Subject: [PATCH 102/148] Fix opening ExHubs connected to a CH via RS-485 --- .../control-hub/src/internal/ControlHub.ts | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 2413c17e..4b55d041 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -555,9 +555,29 @@ export class ControlHubInternal implements ControlHub { } async addChildByAddress(moduleAddress: number): Promise { - return this.addHubBySerialNumberAndAddress(this.serialNumber, moduleAddress); + // Note from Noah: This should not just call addHubBySerialNumberAndAddress(), because that + // will add the hub to usbChildren. + // ToDo(landry): Extract the embedded constant somewhere + let id = await this.openHub("(embedded)", this.moduleAddress, moduleAddress); + + let newHub = new ControlHubConnected( + false, + RevHubType.ExpansionHub, + this.sendCommand.bind(this), + "(embedded)", + moduleAddress, + id, + ); + + this.children.push(newHub); + + if (newHub.isParentHub) { + throw new Error("A child hub without a serial number must not be a parent."); + } + return newHub; } + // ToDo(landry): Rename this addUsbConnectedHub (I'm not sure we need all these byX suffixes) async addHubBySerialNumberAndAddress( serialNumber: string, moduleAddress: number, From 64e777ed4aa1af87ce581be4eb3921de42417010 Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 19:24:17 -0500 Subject: [PATCH 103/148] Fix listing ExHubs connected to a CH via RS-485 --- packages/sample/src/open-usb-control-hub.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/sample/src/open-usb-control-hub.ts b/packages/sample/src/open-usb-control-hub.ts index f5ee3116..70e03b51 100644 --- a/packages/sample/src/open-usb-control-hub.ts +++ b/packages/sample/src/open-usb-control-hub.ts @@ -1,4 +1,4 @@ -import { ControlHub } from "@rev-robotics/rev-hub-core"; +import {ControlHub, ParentRevHub} from "@rev-robotics/rev-hub-core"; import { ControlHubInternal } from "@rev-robotics/control-hub/dist/internal/ControlHub.js"; import { openUsbControlHubs } from "./adb-setup.js"; @@ -18,15 +18,20 @@ export async function openUsbControlHubsAndChildren(): Promise { > = await controlHub.sendCommand("scanAndDiscover", {}, 20000); for (let serialNumber in addresses) { - if (serialNumber === "(embedded)") continue; + let parentHub: ParentRevHub; + let childAddresses = addresses[serialNumber].childAddresses; - let parentHubInfo = addresses[serialNumber]; - let parentHub = await controlHub.addHubBySerialNumberAndAddress( - serialNumber, - parentHubInfo.parentHubAddress, - ); + if (serialNumber === "(embedded)") { + parentHub = controlHub; + } else { + let parentHubInfo = addresses[serialNumber]; + parentHub = await controlHub.addHubBySerialNumberAndAddress( + serialNumber, + parentHubInfo.parentHubAddress, + ); + } - for (let childAddress of parentHubInfo.childAddresses) { + for (let childAddress of childAddresses) { await parentHub.addChildByAddress(childAddress); } } From ab05dfe4abe3b61b070717ab3eb6d6675fc3f04d Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 19:27:49 -0500 Subject: [PATCH 104/148] Don't list the Control Hub as its own child --- packages/control-hub/src/internal/ControlHub.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 4b55d041..86b440c7 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -126,8 +126,6 @@ export class ControlHubInternal implements ControlHub { this.id, ); - this.children.push(this.embedded); - if ( apiVersion.majorVersion !== this.supportedManualControlMajorVersion || apiVersion.minorVersion < this.supportedManualControlMinorVersion From 37dfcdc727c57843be0beb48e063eb83e8727f4d Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 20:12:23 -0500 Subject: [PATCH 105/148] Fix motor in open loop mode connected to CH not stopping immediately --- packages/control-hub/src/internal/ControlHub.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index 86b440c7..df669c41 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -183,8 +183,12 @@ export class ControlHubInternal implements ControlHub { }); } + // ToDo(landry): Always call close() on the parent hub when the sample exits close() { this.embedded.close(); + console.log("Sending stop command"); + // noinspection JSIgnoredPromiseFromCall + this.sendCommand("stop", {}); this.webSocketConnection.close(); } From f71f7b5c94c2ffe1b1445cb78951fec40765b9a1 Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 20:38:41 -0500 Subject: [PATCH 106/148] Fix motor in open loop mode connected to ExHub not stopping immediately --- packages/control-hub/src/internal/ControlHubConnected.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/control-hub/src/internal/ControlHubConnected.ts b/packages/control-hub/src/internal/ControlHubConnected.ts index f741641d..920aa707 100644 --- a/packages/control-hub/src/internal/ControlHubConnected.ts +++ b/packages/control-hub/src/internal/ControlHubConnected.ts @@ -54,7 +54,12 @@ export class ControlHubConnected implements ParentExpansionHub { return this.isParentHub; } - close(): void {} + close(): void { + // noinspection JSIgnoredPromiseFromCall + this.sendCommand("closeHub", { + hId: this.id, + }); + } async getAnalogInput(channel: number): Promise { return await this.sendCommand("getAnalogInput", { From 92ef94a9a0840ca46ad11375bd92e41b4eb2b6d1 Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 20:49:58 -0500 Subject: [PATCH 107/148] Add bug report in TODO --- packages/sample/src/command/motor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/sample/src/command/motor.ts b/packages/sample/src/command/motor.ts index de8c7c39..97a60694 100644 --- a/packages/sample/src/command/motor.ts +++ b/packages/sample/src/command/motor.ts @@ -57,6 +57,7 @@ export async function runEncoder( if (!continuous) break; } hub.close(); + // ToDo(landry): Somehow, when continuous is false, code placed here gets executed, but the program doesn't exit without Ctrl-C } export async function resetEncoder(hub: ExpansionHub, channel: number) { From 49534b848a780caf3603a4389c21a5f3bad19472 Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 20:52:13 -0500 Subject: [PATCH 108/148] Fix bulkInput command (old version was interpreted as needing an argument) --- packages/sample/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index ab135028..b0cc2094 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -77,7 +77,7 @@ program await led(hubs[0], rValue, gValue, bValue); }); -program.command("bulk input").action(async () => { +program.command("bulkInput").action(async () => { let hubs = await openUsbControlHubs(); await getBulkInputData(hubs[0]); }); From 89969332ff4e29ee32e4a4742328ec382c5164fa Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 21:05:45 -0500 Subject: [PATCH 109/148] Fix program name for demo --- packages/sample/src/main.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index b0cc2094..5e757cf7 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -29,6 +29,8 @@ import { getBulkInputData } from "./command/bulkinput.js"; const program = new Command(); +program.name("ch"); + program.version("1.0.0"); program From 0a96a07c989b904b1e5dbf39e5db6294bf016792 Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 21:06:59 -0500 Subject: [PATCH 110/148] Add missing space --- packages/sample/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 5e757cf7..5bd4b806 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -189,7 +189,7 @@ program .command("analog ") .option("--continuous", "Run continuously") .description( - "Read the analog value of the given port. Specify" + + "Read the analog value of the given port. Specify " + "--continuous to run continuously.", ) .action(async (port, options) => { From 0d2d6b8502b913776bc5c98838ca647d82491bd2 Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 21:08:29 -0500 Subject: [PATCH 111/148] Improve name of 5V rail command --- packages/sample/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index 5bd4b806..f7065379 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -213,7 +213,7 @@ program }); program - .command("voltage") + .command("5vRailVoltage") .option("--continuous", "Run continuously") .description( "Read the current 5V rail voltage. Specify --continuous to run continuously", From 46eb5dc6640c45ba0034cc53d70081eafd2aba3a Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 21:11:36 -0500 Subject: [PATCH 112/148] Fix TimeoutError when closing Control Hub --- packages/control-hub/src/internal/ControlHub.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/control-hub/src/internal/ControlHub.ts b/packages/control-hub/src/internal/ControlHub.ts index df669c41..29e103e2 100644 --- a/packages/control-hub/src/internal/ControlHub.ts +++ b/packages/control-hub/src/internal/ControlHub.ts @@ -186,10 +186,8 @@ export class ControlHubInternal implements ControlHub { // ToDo(landry): Always call close() on the parent hub when the sample exits close() { this.embedded.close(); - console.log("Sending stop command"); - // noinspection JSIgnoredPromiseFromCall - this.sendCommand("stop", {}); - this.webSocketConnection.close(); + this.sendCommand("stop", {}) + .then(() => this.webSocketConnection.close()); } async getAnalogInput(channel: number): Promise { From f2465673c242d5ceae3371e23a32f2f6a9ca59cf Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Fri, 16 Jun 2023 21:13:00 -0500 Subject: [PATCH 113/148] Disable distance command for demo I'm not sure, but the code for I2C on this branch looked broken to me --- packages/sample/src/main.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/sample/src/main.ts b/packages/sample/src/main.ts index f7065379..9e0d752d 100644 --- a/packages/sample/src/main.ts +++ b/packages/sample/src/main.ts @@ -248,15 +248,15 @@ program await runServo(hub, channelValue, pulseWidthValue, frameWidthValue); }); -program - .command("distance ") - .option("--continuous", "run continuously") - .description("Read distance from a REV 2m distance sensor") - .action(async (channel, options): Promise => { - let isContinuous = options.continuous !== undefined; - let channelNumber = Number(channel); - await distance(channelNumber, isContinuous); - }); +// program +// .command("distance ") +// .option("--continuous", "run continuously") +// .description("Read distance from a REV 2m distance sensor") +// .action(async (channel, options): Promise => { +// let isContinuous = options.continuous !== undefined; +// let channelNumber = Number(channel); +// await distance(channelNumber, isContinuous); +// }); program.parse(process.argv); From 9330e33a7ebfd2699219cab46e8fe1186017475f Mon Sep 17 00:00:00 2001 From: LandryNorris Date: Tue, 20 Jun 2023 11:46:55 -0500 Subject: [PATCH 114/148] require user to specify led pattern steps --- packages/sample/src/command/led.ts | 52 +++++++++++++++++++++++ packages/sample/src/command/ledPattern.ts | 29 ------------- packages/sample/src/main.ts | 26 +++++++----- 3 files changed, 68 insertions(+), 39 deletions(-) create mode 100644 packages/sample/src/command/led.ts delete mode 100644 packages/sample/src/command/ledPattern.ts diff --git a/packages/sample/src/command/led.ts b/packages/sample/src/command/led.ts new file mode 100644 index 00000000..ade50913 --- /dev/null +++ b/packages/sample/src/command/led.ts @@ -0,0 +1,52 @@ +import { + createLedPattern, + LedPatternStep, + openConnectedExpansionHubs, +} from "@rev-robotics/expansion-hub"; +import { ExpansionHub } from "@rev-robotics/rev-hub-core"; +import { openUsbControlHubs } from "../adb-setup.js"; +export async function ledPattern(hub: ExpansionHub, args: string[]) { + function parse(step: string): LedPatternStep { + function hex2rgb(hex: string) { + let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result + ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16), + } + : undefined; + } + if (step.length < 6) { + throw new Error( + "Please pass steps in the format