From 22a44868457844f518c9596008223b05bd226ed3 Mon Sep 17 00:00:00 2001 From: Sterling Hirsh Date: Fri, 30 Oct 2020 02:23:32 -0500 Subject: [PATCH 1/5] Add isSupported() to Device class This lets us load the package for unsupported devices without crashing. There are probably more incompatibilities, but the windows DACs were the ones causing a problem for me. --- packages/beyond/src/BeyondLib.ts | 5 ++++- packages/beyond/src/index.ts | 7 +++++++ packages/core/src/index.ts | 4 ++++ packages/easylase/src/EasylaseLib.ts | 5 ++++- packages/easylase/src/index.ts | 8 ++++++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/beyond/src/BeyondLib.ts b/packages/beyond/src/BeyondLib.ts index 7393a3e..405c82a 100644 --- a/packages/beyond/src/BeyondLib.ts +++ b/packages/beyond/src/BeyondLib.ts @@ -26,7 +26,10 @@ const libPath = path // dont'get placed inside the "app.asar" bundle, but instead get placed in a separate directory called "app.asar.unpacked" .replace('app.asar', 'app.asar.unpacked'); -const BeyondLib = ffi.Library(libPath, { +// Even Windows 64-bit is called win32 here. +const isSupported = process.platform === "win32"; + +const BeyondLib = isSupported && ffi.Library(libPath, { ldbCreate: ['int', []], ldbDestroy: ['int', []], ldbBeyondExeReady: ['int', []], diff --git a/packages/beyond/src/index.ts b/packages/beyond/src/index.ts index b107e9d..8f73305 100644 --- a/packages/beyond/src/index.ts +++ b/packages/beyond/src/index.ts @@ -13,6 +13,9 @@ export class Beyond extends Device { private started = false; async start() { + if (!this.isSupported()) { + return false; + } this.stop(); beyondLib.ldbCreate(); this.started = true; @@ -37,6 +40,10 @@ export class Beyond extends Device { } } + isSupported(): boolean { + return process.platform === "win32"; + } + private convertPoint(p: Point) { return { x: relativeToPosition(p.x), diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 142d35f..c42dffd 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -17,6 +17,10 @@ export abstract class Device { abstract start(): Promise; abstract stop(): void; abstract stream(scene: Scene, pointsRate: number, fps: number): void; + + isSupported(): boolean { + return true; + }; } export class DAC { diff --git a/packages/easylase/src/EasylaseLib.ts b/packages/easylase/src/EasylaseLib.ts index aabbc05..8de5bfc 100644 --- a/packages/easylase/src/EasylaseLib.ts +++ b/packages/easylase/src/EasylaseLib.ts @@ -37,7 +37,10 @@ const libPath = path // dont'get placed inside the "app.asar" bundle, but instead get placed in a separate directory called "app.asar.unpacked" .replace('app.asar', 'app.asar.unpacked'); -const EasylaseLib = ffi.Library(libPath, { +// Even Windows 64-bit is called win32 here. +const isSupported = process.platform === "win32"; + +const EasylaseLib = isSupported && ffi.Library(libPath, { jmLaserEnumerateDevices: ['int', []], jmLaserStopOutput: ['int', ['int']], jmLaserCloseDevice: ['int', ['int']], diff --git a/packages/easylase/src/index.ts b/packages/easylase/src/index.ts index bdb82ee..b0ecb30 100644 --- a/packages/easylase/src/index.ts +++ b/packages/easylase/src/index.ts @@ -7,6 +7,10 @@ export class Easylase extends Device { deviceHandle?: number; async start() { + if (!this.isSupported()) { + return false; + } + this.stop(); const cards = easylaseLib.enumerateDevices(); if (cards) { @@ -32,6 +36,10 @@ export class Easylase extends Device { } } + isSupported(): boolean { + return process.platform === "win32"; + } + private convertPoint(p: Point) { return { x: relativeToPosition(p.x), From cdad4b89eef2722e2abe7e00c2b350883dc1068c Mon Sep 17 00:00:00 2001 From: Sterling Hirsh Date: Fri, 30 Oct 2020 02:43:20 -0500 Subject: [PATCH 2/5] Add device-selector: auto-select a DAC + Simulator --- packages/core/src/index.ts | 4 ++ packages/device-selector/README.md | 35 +++++++++++++ packages/device-selector/package.json | 35 +++++++++++++ packages/device-selector/src/index.ts | 52 ++++++++++++++++++++ packages/device-selector/tsconfig.build.json | 8 +++ 5 files changed, 134 insertions(+) create mode 100644 packages/device-selector/README.md create mode 100644 packages/device-selector/package.json create mode 100644 packages/device-selector/src/index.ts create mode 100644 packages/device-selector/tsconfig.build.json diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c42dffd..ac74c11 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -30,6 +30,10 @@ export class DAC { this.devices.push(device); } + useAll(devices: Device[]) { + devices.forEach((device) => this.use(device)); + } + remove(device: Device) { const index = this.devices.indexOf(device); if (index) { diff --git a/packages/device-selector/README.md b/packages/device-selector/README.md new file mode 100644 index 0000000..5d7e972 --- /dev/null +++ b/packages/device-selector/README.md @@ -0,0 +1,35 @@ +# @laser-dac/device-selector + +This package is an easy adapter for multiple devices. + +``` +yarn add @laser-dac/device-selector +npm i @laser-dac/device-selector +``` + +## Usage + +```js +import { DAC } from '@laser-dac/core'; +import { getDevices } from '@laser-dac/device-selector'; + +const dac = new DAC(); +// Automatically select a supported device and a Simulator. +dac.useAll(await getDevices()); +const started = await dac.start(); +if (started) { + const pps = 30000; // points per second + const fps = 120; // frames per second + // draw a horizontal red line from left to right in the center + // @laser-dac/draw can help you with drawing points! + const scene = { + points: [ + { x: 0.1, y: 0.5, r: 1, g: 0, b: 0 }, + { x: 0.9, y: 0.5, r: 1, g: 0, b: 0 } + ] + }; + dac.stream(scene, pps, fps); +} +``` + +See for more usage info and examples the [Laser DAC project on GitHub](https://github.com/Volst/laser-dac). diff --git a/packages/device-selector/package.json b/packages/device-selector/package.json new file mode 100644 index 0000000..4d78c84 --- /dev/null +++ b/packages/device-selector/package.json @@ -0,0 +1,35 @@ +{ + "name": "@laser-dac/device-selector", + "version": "0.4.1", + "description": "Device-selecting adapter for laser-dac", + "license": "MIT", + "author": "Sterling Hirsh ", + "repository": "Volst/laser-dac", + "keywords": [ + "laser" + ], + "engines": { + "node": ">=8.0" + }, + "main": "dist/index.js", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@laser-dac/core": "^0.4.1", + "@laser-dac/beyond": "^0.3.0", + "@laser-dac/easylase": "^0.2.0", + "@laser-dac/ether-dream": "^0.4.1", + "@laser-dac/helios": "^0.3.0", + "@laser-dac/laserdock": "^0.4.0", + "@laser-dac/simulator": "^0.3.3" + }, + "scripts": { + "build": "rm -rf dist && tsc -p tsconfig.build.json", + "watch": "tsc -p tsconfig.build.json --watch", + "prepublishOnly": "npm run -s build" + } +} diff --git a/packages/device-selector/src/index.ts b/packages/device-selector/src/index.ts new file mode 100644 index 0000000..f916c4d --- /dev/null +++ b/packages/device-selector/src/index.ts @@ -0,0 +1,52 @@ +import { Device } from '@laser-dac/core'; + +import { Simulator } from '@laser-dac/simulator'; + +import { Beyond } from '@laser-dac/beyond'; +import { Easylase } from '@laser-dac/easylase'; +import { EtherDream } from '@laser-dac/ether-dream'; +import { Helios } from '@laser-dac/helios'; +import { Laserdock } from '@laser-dac/laserdock'; + +const apis: Record = { + helios: Helios, + laserdock: Laserdock, + beyond: Beyond, + easylase: Easylase, + 'ether-dream': EtherDream // This one is a bit slower to check. +}; + +// Get the first DAC that works. +export async function autoSelect(): Promise { + console.log("Searching for DAC in " + Object.keys(apis).join(', ')); + for (const api in apis) { + const dac = new apis[api](); + if (await dac.start()) { + console.log("Auto Selected DAC " + api); + await dac.stop(); + return dac; + } + } + console.log("No DAC found"); + return null; +} + +// Get a Simulator and the first autodetected device. +// TODO: Get multiple devices instead of just the first? +export async function getDevices(): Promise { + const devices: Device[] = [new Simulator()]; + const requestedDevice = process.env.DEVICE; + + if (requestedDevice) { + if (requestedDevice in apis) { + devices.push(new apis[requestedDevice]()); + } else { + const autoSelected = await autoSelect(); + if (autoSelected) { + devices.push(autoSelected); + } + } + } + + return devices; +} diff --git a/packages/device-selector/tsconfig.build.json b/packages/device-selector/tsconfig.build.json new file mode 100644 index 0000000..5a2694a --- /dev/null +++ b/packages/device-selector/tsconfig.build.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/index.ts"] +} From 37eea41587fd1cb23ae85b44346fd506c97c3aa0 Mon Sep 17 00:00:00 2001 From: Sterling Hirsh Date: Fri, 30 Oct 2020 03:07:56 -0500 Subject: [PATCH 3/5] Use device-selector instead of hard-coding devices --- .gitignore | 2 ++ examples/static-shapes/index.ts | 8 ++------ examples/svg-path/index.ts | 9 +++------ 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 3c25e1e..dc9966e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules/ dist/ *.log +*.swp +*.swo diff --git a/examples/static-shapes/index.ts b/examples/static-shapes/index.ts index 5301ea3..b0ab64e 100644 --- a/examples/static-shapes/index.ts +++ b/examples/static-shapes/index.ts @@ -1,14 +1,10 @@ import { DAC } from '@laser-dac/core'; -import { Simulator } from '@laser-dac/simulator'; -import { Helios } from '@laser-dac/helios'; +import { getDevices } from '@laser-dac/device-selector'; import { Scene, Rect, Path, Line } from '@laser-dac/draw'; (async () => { const dac = new DAC(); - dac.use(new Simulator()); - if (process.env.DEVICE) { - dac.use(new Helios()); - } + dac.useAll(await getDevices()); await dac.start(); const scene = new Scene({ diff --git a/examples/svg-path/index.ts b/examples/svg-path/index.ts index bd71d1a..54df4fe 100644 --- a/examples/svg-path/index.ts +++ b/examples/svg-path/index.ts @@ -1,6 +1,5 @@ import { DAC } from '@laser-dac/core'; -import { Simulator } from '@laser-dac/simulator'; -import { EtherDream } from '@laser-dac/ether-dream'; +import { getDevices } from '@laser-dac/device-selector'; import { Scene, Svg, loadSvgFile } from '@laser-dac/draw'; import * as path from 'path'; @@ -8,10 +7,8 @@ const logoFile = loadSvgFile(path.resolve(__dirname, './logo.svg')); (async () => { const dac = new DAC(); - dac.use(new Simulator()); - if (process.env.DEVICE) { - dac.use(new EtherDream()); - } + dac.useAll(await getDevices()); + await dac.start(); const scene = new Scene({ From b901dc3ffd22f454f696fb56c1c787754a29db94 Mon Sep 17 00:00:00 2001 From: Sterling Hirsh Date: Fri, 30 Oct 2020 12:42:11 -0500 Subject: [PATCH 4/5] Balls: update example for device-selector There's some other problems with this example but those changes will come later. --- examples/balls/index.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/balls/index.ts b/examples/balls/index.ts index d75dcb8..bd6f00a 100644 --- a/examples/balls/index.ts +++ b/examples/balls/index.ts @@ -1,6 +1,5 @@ import { DAC } from '@laser-dac/core'; -import { Simulator } from '@laser-dac/simulator'; -import { EtherDream } from '@laser-dac/ether-dream'; +import { getDevices } from '@laser-dac/device-selector'; import { Scene, Rect } from '@laser-dac/draw'; import { Ball } from './Ball'; @@ -8,10 +7,7 @@ const NUMBER_OF_BALLS = 4; (async () => { const dac = new DAC(); - dac.use(new Simulator()); - if (process.env.DEVICE) { - dac.use(new EtherDream()); - } + dac.useAll(await getDevices()); await dac.start(); const balls: Ball[] = []; From b7d16c8022009f244778e90d2d6cef504600c937 Mon Sep 17 00:00:00 2001 From: Sterling Hirsh Date: Fri, 30 Oct 2020 13:29:24 -0500 Subject: [PATCH 5/5] Use device-selector in remaining examples --- examples/font/index.ts | 8 ++------ examples/ilda-animation/index.ts | 8 ++------ examples/pong/renderer.ts | 8 ++------ examples/square-interactive/renderer.ts | 8 ++------ 4 files changed, 8 insertions(+), 24 deletions(-) diff --git a/examples/font/index.ts b/examples/font/index.ts index 3c0cd46..a172261 100644 --- a/examples/font/index.ts +++ b/examples/font/index.ts @@ -1,6 +1,5 @@ import { DAC } from '@laser-dac/core'; -import { Simulator } from '@laser-dac/simulator'; -import { EtherDream } from '@laser-dac/ether-dream'; +import { getDevices } from '@laser-dac/device-selector'; import { Scene, HersheyFont, loadHersheyFont, Timeline } from '@laser-dac/draw'; import * as path from 'path'; @@ -38,10 +37,7 @@ const textAnimation = new Timeline({ (async () => { const dac = new DAC(); - dac.use(new Simulator()); - if (process.env.DEVICE) { - dac.use(new EtherDream()); - } + dac.useAll(await getDevices()); await dac.start(); const scene = new Scene(); diff --git a/examples/ilda-animation/index.ts b/examples/ilda-animation/index.ts index f97fcf8..648a36a 100644 --- a/examples/ilda-animation/index.ts +++ b/examples/ilda-animation/index.ts @@ -1,6 +1,5 @@ import { DAC } from '@laser-dac/core'; -import { Simulator } from '@laser-dac/simulator'; -import { EtherDream } from '@laser-dac/ether-dream'; +import { getDevices } from '@laser-dac/device-selector'; import { Scene, Ilda, loadIldaFile } from '@laser-dac/draw'; import * as path from 'path'; @@ -8,10 +7,7 @@ const boeing = loadIldaFile(path.resolve(__dirname, './boeing.ild')); (async () => { const dac = new DAC(); - dac.use(new Simulator()); - if (process.env.DEVICE) { - dac.use(new EtherDream()); - } + dac.useAll(await getDevices()); await dac.start(); const scene = new Scene(); diff --git a/examples/pong/renderer.ts b/examples/pong/renderer.ts index 81d3e97..a77e5bd 100644 --- a/examples/pong/renderer.ts +++ b/examples/pong/renderer.ts @@ -1,6 +1,5 @@ import { DAC } from '@laser-dac/core'; -import { Simulator } from '@laser-dac/simulator'; -import { EtherDream } from '@laser-dac/ether-dream'; +import { getDevices } from '@laser-dac/device-selector'; import { Scene, Rect } from '@laser-dac/draw'; import { Player } from './Player'; import { Ball } from './Ball'; @@ -27,10 +26,7 @@ export class Renderer { async start() { const dac = new DAC(); - dac.use(new Simulator()); - if (process.env.DEVICE) { - dac.use(new EtherDream()); - } + dac.useAll(await getDevices()); await dac.start(); const ball = new Ball({ diff --git a/examples/square-interactive/renderer.ts b/examples/square-interactive/renderer.ts index c71ddf1..495761c 100755 --- a/examples/square-interactive/renderer.ts +++ b/examples/square-interactive/renderer.ts @@ -1,6 +1,5 @@ import { DAC } from '@laser-dac/core'; -import { Simulator } from '@laser-dac/simulator'; -import { EtherDream } from '@laser-dac/ether-dream'; +import { getDevices } from '@laser-dac/device-selector'; import { Scene, Rect, loadIldaFile, Ilda } from '@laser-dac/draw'; import * as path from 'path'; @@ -48,10 +47,7 @@ export class Renderer { async start() { const dac = new DAC(); - dac.use(new Simulator()); - if (process.env.DEVICE) { - dac.use(new EtherDream()); - } + dac.useAll(await getDevices()); await dac.start(); const scene = new Scene();