mirror of
https://github.com/rainloreley/artnet-usbdmx-converter.git
synced 2025-01-02 23:14:54 +01:00
Compare commits
10 Commits
876dc890e5
...
f36cc53be1
Author | SHA1 | Date | |
---|---|---|---|
f36cc53be1 | |||
bef4f63315 | |||
faccdb1e2f | |||
dba240beb2 | |||
c8448c56ba | |||
07d78f084b | |||
5df38d6d0e | |||
a6e1dedc41 | |||
8128637cfd | |||
52ff5d9d90 |
5
.github/workflows/main.yml
vendored
5
.github/workflows/main.yml
vendored
@ -1,8 +1,5 @@
|
|||||||
name: Build app
|
name: Build app
|
||||||
on:
|
on: workflow_dispatch
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ dist
|
|||||||
out/
|
out/
|
||||||
.idea/
|
.idea/
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
appconfig.json
|
68
README.md
68
README.md
@ -56,6 +56,74 @@ $ sudo udevadm control --reload-rules
|
|||||||
- Technically any interface that uses the [usbdmx driver](https://github.com/fx5/usbdmx) by Frank Sievertsen
|
- Technically any interface that uses the [usbdmx driver](https://github.com/fx5/usbdmx) by Frank Sievertsen
|
||||||
- Won't work out of the box, vendor ID and product ID need to be [added manually](./src/usbdmx/index.ts)
|
- Won't work out of the box, vendor ID and product ID need to be [added manually](./src/usbdmx/index.ts)
|
||||||
|
|
||||||
|
# Automatic restart
|
||||||
|
|
||||||
|
To restart the program automatically in case of a crash or another exception, add `--autoretry` as a command line argument.
|
||||||
|
This does not apply in the following cases:
|
||||||
|
- Intentional exit (Crtl+C, "kill" command, closing the terminal)
|
||||||
|
- Invalid configuration file
|
||||||
|
# Configuration File
|
||||||
|
You can optionally add a configuration file containing parameters for the default USBDMX interface
|
||||||
|
and options regarding the ArtNet transceiver.
|
||||||
|
|
||||||
|
To use a configuration file, create a file on your system with the options below. Then start the program with `--config=<path>`
|
||||||
|
as a command line argument. Replace `<path>` with the absolute path to the file.
|
||||||
|
|
||||||
|
## Full config
|
||||||
|
|
||||||
|
You can omit any options that you don't want to change, the program will use the default options instead (except for `"interface"`).
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"interface": {}, // see below
|
||||||
|
"dmxnet": { // config for ArtNet transceiver
|
||||||
|
"main": { // general options
|
||||||
|
"log": {
|
||||||
|
"level": "info", // available: error, warn, info, verbose, debug, silly
|
||||||
|
"oem": 0, // OEM Code from artisticlicense, default to dmxnet OEM.
|
||||||
|
"sName": "Text", // 17 char long node description, default to "usbdmx"
|
||||||
|
"lName": "Long description", // 63 char long node description, default to "ArtNet-USBDMX-Converter"
|
||||||
|
"hosts": ["127.0.0.1"] // Interfaces to listen to, defaults to ["0.0.0.0"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transmitter": { // ArtNet transmitter options (USBDMX In => ArtNet)
|
||||||
|
"ip": "127.0.0.1", // IP to send to, default 255.255.255.255
|
||||||
|
"subnet": 0, // Destination subnet, default 0
|
||||||
|
"universe": 0, // Destination universe, default 0
|
||||||
|
"net": 0, // Destination net, default 0
|
||||||
|
"port": 6454, // Destination UDP Port, default 6454
|
||||||
|
"base_refresh_interval": 1000 // Default interval for sending unchanged ArtDmx
|
||||||
|
},
|
||||||
|
"receiver": { // ArtNet receiver options (ArtNet => USBDMX Out)
|
||||||
|
"subnet": 0, //Destination subnet, default 0
|
||||||
|
"universe": 0, //Destination universe, default 0
|
||||||
|
"net": 0, //Destination net, default 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Generate config for interface
|
||||||
|
To automatically select a USBDMX Interface on startup you need to set its parameters in the configuration file under `"interfaces"`.
|
||||||
|
|
||||||
|
You can generate these parameters by running:
|
||||||
|
```bash
|
||||||
|
$ ./artnet-usbdmx-converter outputconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
Select the interface and mode to use and copy the output to `"interface"` inside the configuration file.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"interface": {
|
||||||
|
"serial": "0000000010000492",
|
||||||
|
"mode": "6",
|
||||||
|
"manufacturer": "Digital Enlightenment",
|
||||||
|
"product": "USB DMX"
|
||||||
|
},
|
||||||
|
[...]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# Develop & Build
|
# Develop & Build
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "artnet-usbdmx-converter",
|
"name": "artnet-usbdmx-converter",
|
||||||
"version": "1.0.0",
|
"version": "2.0.0",
|
||||||
"description": "Send ArtNet signals to USBDMX interfaces",
|
"description": "Send ArtNet signals to USBDMX interfaces",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"bin": "./dist/index.js",
|
"bin": "./dist/index.js",
|
||||||
@ -34,6 +34,7 @@
|
|||||||
"dmxnet": "^0.9.0",
|
"dmxnet": "^0.9.0",
|
||||||
"figlet": "^1.6.0",
|
"figlet": "^1.6.0",
|
||||||
"inquirer": "8.0.0",
|
"inquirer": "8.0.0",
|
||||||
|
"minimist": "^1.2.8",
|
||||||
"node-hid": "^2.1.2"
|
"node-hid": "^2.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -41,6 +42,7 @@
|
|||||||
"@types/clui": "^0.3.2",
|
"@types/clui": "^0.3.2",
|
||||||
"@types/figlet": "^1.5.6",
|
"@types/figlet": "^1.5.6",
|
||||||
"@types/inquirer": "^9.0.3",
|
"@types/inquirer": "^9.0.3",
|
||||||
|
"@types/minimist": "^1.2.5",
|
||||||
"@types/node": "^20.8.3",
|
"@types/node": "^20.8.3",
|
||||||
"@types/node-hid": "^1.3.4",
|
"@types/node-hid": "^1.3.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {dmxnet, receiver} from "dmxnet";
|
import {dmxnet, receiver, sender} from "dmxnet";
|
||||||
import {DetectedInterface, DMXInterface, getConnectedInterfaces} from "./usbdmx";
|
import {DetectedInterface, DMXInterface, getConnectedInterfaces} from "./usbdmx";
|
||||||
import {clearInterval} from "timers";
|
import {clearInterval} from "timers";
|
||||||
|
import {defaultConfigStorage} from "./index";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for converting incoming Art-Net data to an USBDMX output
|
* Responsible for converting incoming Art-Net data to an USBDMX output
|
||||||
@ -8,6 +9,7 @@ import {clearInterval} from "timers";
|
|||||||
export default class ConvertHandler {
|
export default class ConvertHandler {
|
||||||
dmxnetManager: dmxnet;
|
dmxnetManager: dmxnet;
|
||||||
artNetReceiver: receiver;
|
artNetReceiver: receiver;
|
||||||
|
artNetSender: sender;
|
||||||
|
|
||||||
recentDMXArray: number[] = Array(512).fill(0);
|
recentDMXArray: number[] = Array(512).fill(0);
|
||||||
|
|
||||||
@ -16,39 +18,60 @@ export default class ConvertHandler {
|
|||||||
dmxInterface: DMXInterface | undefined;
|
dmxInterface: DMXInterface | undefined;
|
||||||
outputAllowed = false;
|
outputAllowed = false;
|
||||||
|
|
||||||
incomingDataCounter = 0;
|
|
||||||
sentDataCounter = 0;
|
|
||||||
dataPerSecTimer: NodeJS.Timeout;
|
dataPerSecTimer: NodeJS.Timeout;
|
||||||
incomingDataHistory: number[] = [];
|
|
||||||
sentDataHistory: number[] = [];
|
private artnetInCounter = 0;
|
||||||
|
private artnetOutCounter = 0;
|
||||||
|
private usbdmxInCounter = 0;
|
||||||
|
private usbdmxOutCounter = 0;
|
||||||
|
|
||||||
|
artnetInCountHistory: number[] = [];
|
||||||
|
artnetOutCountHistory: number[] = [];
|
||||||
|
usbdmxInCountHistory: number[] = [];
|
||||||
|
usbdmxOutCountHistory: number[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts up the Art-Net receiver
|
* Starts up the Art-Net receiver
|
||||||
*/
|
*/
|
||||||
startArtNetReceiver = () => {
|
startArtNetReceiver = () => {
|
||||||
this.dmxnetManager = new dmxnet({
|
this.dmxnetManager = new dmxnet(defaultConfigStorage.getDmxNetConfig());
|
||||||
log: {level: "error"}
|
this.artNetReceiver = this.dmxnetManager.newReceiver(defaultConfigStorage.getDmxNetReceiverConfig());
|
||||||
});
|
this.artNetSender = this.dmxnetManager.newSender(defaultConfigStorage.getDmxNetSenderConfig());
|
||||||
this.artNetReceiver = this.dmxnetManager.newReceiver();
|
|
||||||
this.artNetReceiver.on("data", this.handleIncomingArtNetData);
|
this.artNetReceiver.on("data", this.handleIncomingArtNetData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles incoming Art-Net dara and writes it to the DMX interface
|
* Handles incoming Art-Net data and writes it to the DMX interface.
|
||||||
* @param data Art-Net data
|
* @param data Art-Net data
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
handleIncomingArtNetData = (data: any) => {
|
handleIncomingArtNetData = (data: any) => {
|
||||||
this.incomingDataCounter++;
|
this.artnetInCounter++;
|
||||||
if (JSON.stringify(data) != JSON.stringify(this.recentDMXArray)) {
|
if (JSON.stringify(data) != JSON.stringify(this.recentDMXArray)) {
|
||||||
if (this.dmxInterface && this.outputAllowed) {
|
if (this.dmxInterface && this.outputAllowed) {
|
||||||
this.sentDataCounter++;
|
this.usbdmxOutCounter++;
|
||||||
this.dmxInterface.writeMap(data);
|
this.dmxInterface.writeMap(data);
|
||||||
}
|
}
|
||||||
this.recentDMXArray = data;
|
this.recentDMXArray = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles incoming data from the interface and sends it out via Art-Net.
|
||||||
|
* @param startChannel first channel number of the data array
|
||||||
|
* @param data Array with dmx values
|
||||||
|
*/
|
||||||
|
sendIncomingUSBDMXData = (startChannel: number, data: number[]) => {
|
||||||
|
this.usbdmxInCounter++;
|
||||||
|
if (this.outputAllowed) {
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
this.artNetSender.prepChannel(startChannel + i, data[i]);
|
||||||
|
}
|
||||||
|
this.artnetOutCounter++;
|
||||||
|
this.artNetSender.transmit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets available DMX interfaces connected to the computer
|
* Gets available DMX interfaces connected to the computer
|
||||||
*/
|
*/
|
||||||
@ -75,6 +98,7 @@ export default class ConvertHandler {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
this.dmxInterface = await DMXInterface.open(interfacePath, serial, manufacturer, product);
|
this.dmxInterface = await DMXInterface.open(interfacePath, serial, manufacturer, product);
|
||||||
|
this.dmxInterface.usbdmxInputCallback = this.sendIncomingUSBDMXData;
|
||||||
return new Promise<string>((resolve) => {
|
return new Promise<string>((resolve) => {
|
||||||
setTimeout( () => {
|
setTimeout( () => {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
@ -108,16 +132,29 @@ export default class ConvertHandler {
|
|||||||
* Processes incoming and sent data history for visualization
|
* Processes incoming and sent data history for visualization
|
||||||
*/
|
*/
|
||||||
parseRequestTimer = () => {
|
parseRequestTimer = () => {
|
||||||
this.incomingDataHistory.push(this.incomingDataCounter);
|
this.artnetInCountHistory.push(this.artnetInCounter);
|
||||||
if (this.incomingDataHistory.length > 20) {
|
if (this.artnetInCountHistory.length > 20) {
|
||||||
this.incomingDataHistory = this.incomingDataHistory.slice(1)
|
this.artnetInCountHistory = this.artnetInCountHistory.slice(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sentDataHistory.push(this.sentDataCounter);
|
this.artnetOutCountHistory.push(this.artnetOutCounter);
|
||||||
if (this.sentDataHistory.length > 20) {
|
if (this.artnetOutCountHistory.length > 20) {
|
||||||
this.sentDataHistory = this.sentDataHistory.slice(1)
|
this.artnetOutCountHistory = this.artnetOutCountHistory.slice(1)
|
||||||
}
|
}
|
||||||
this.incomingDataCounter = 0;
|
|
||||||
this.sentDataCounter = 0;
|
this.usbdmxInCountHistory.push(this.usbdmxInCounter);
|
||||||
|
if (this.usbdmxInCountHistory.length > 20) {
|
||||||
|
this.usbdmxInCountHistory = this.usbdmxInCountHistory.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.usbdmxOutCountHistory.push(this.usbdmxOutCounter);
|
||||||
|
if (this.usbdmxOutCountHistory.length > 20) {
|
||||||
|
this.usbdmxOutCountHistory = this.usbdmxOutCountHistory.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.artnetInCounter = 0;
|
||||||
|
this.artnetOutCounter = 0;
|
||||||
|
this.usbdmxInCounter = 0;
|
||||||
|
this.usbdmxOutCounter = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
70
src/config/ConfigStorage.ts
Normal file
70
src/config/ConfigStorage.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/***********************************
|
||||||
|
* src/config/ConfigStorage.ts
|
||||||
|
*
|
||||||
|
* Created on 08.05.24 by adrian
|
||||||
|
* Project: artnet-usbdmx-converter
|
||||||
|
*************************************/
|
||||||
|
|
||||||
|
import * as fs from "fs";
|
||||||
|
import {StartupScreenResponse} from "../startupscreen";
|
||||||
|
import {DmxnetOptions, ReceiverOptions, SenderOptions} from "dmxnet";
|
||||||
|
|
||||||
|
export default class ConfigStorage {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
private data: any
|
||||||
|
|
||||||
|
loadConfig(path: string) {
|
||||||
|
let filedata: string
|
||||||
|
try {
|
||||||
|
filedata = fs.readFileSync(path, "utf-8")
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to read file!")
|
||||||
|
console.error(e)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.data = JSON.parse(filedata);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("JSON file contains error!")
|
||||||
|
console.error(e)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getInterface(): StartupScreenResponse | undefined {
|
||||||
|
return this.data?.interface as StartupScreenResponse ?? undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDmxNetConfig(): DmxnetOptions {
|
||||||
|
const mainConfig = this.data?.dmxnet?.main;
|
||||||
|
return {
|
||||||
|
log: mainConfig?.log ?? {level: "error"},
|
||||||
|
oem: mainConfig?.oem ?? undefined,
|
||||||
|
sName: mainConfig?.sName ?? "usbdmx",
|
||||||
|
lName: mainConfig?.lName ?? "ArtNet-USBDMX-Converter",
|
||||||
|
hosts: mainConfig?.hosts ?? ["0.0.0.0"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDmxNetReceiverConfig(): ReceiverOptions {
|
||||||
|
const receiverConfig = this.data?.dmxnet?.receiver;
|
||||||
|
return {
|
||||||
|
subnet: receiverConfig?.subnet ?? 0,
|
||||||
|
universe: receiverConfig?.universe ?? 0,
|
||||||
|
net: receiverConfig?.net ?? 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDmxNetSenderConfig(): SenderOptions {
|
||||||
|
const transmitterConfig = this.data?.dmxnet?.transmitter;
|
||||||
|
return {
|
||||||
|
ip: transmitterConfig?.ip ?? "255.255.255.255",
|
||||||
|
subnet: transmitterConfig?.subnet ?? 0,
|
||||||
|
universe: transmitterConfig?.universe ?? 0,
|
||||||
|
net: transmitterConfig?.net ?? 0,
|
||||||
|
port: transmitterConfig?.port ?? 6454,
|
||||||
|
base_refresh_interval: transmitterConfig?.base_refresh_interval ?? 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -36,16 +36,22 @@ export default async function renderControlScreen() {
|
|||||||
`${modeToString(defaultConvertHandler.dmxInterface?.currentMode ?? 0)}`)
|
`${modeToString(defaultConvertHandler.dmxInterface?.currentMode ?? 0)}`)
|
||||||
console.log("=================")
|
console.log("=================")
|
||||||
|
|
||||||
const incomingDataSparkline = Sparkline(defaultConvertHandler.incomingDataHistory, "req/sec");
|
const artnetInSparkline = Sparkline(defaultConvertHandler.artnetInCountHistory, "req/sec");
|
||||||
const sentDataSparkline = Sparkline(defaultConvertHandler.sentDataHistory, "req/sec");
|
const artnetOutSparkline = Sparkline(defaultConvertHandler.artnetOutCountHistory, "req/sec");
|
||||||
|
const usbdmxInSparkline = Sparkline(defaultConvertHandler.usbdmxInCountHistory, "req/sec");
|
||||||
|
const usbdmxOutSparkline = Sparkline(defaultConvertHandler.usbdmxOutCountHistory, "req/sec");
|
||||||
|
|
||||||
process.stdout.write("Incoming Data ")
|
process.stdout.write("ArtNet In\t")
|
||||||
process.stdout.write(incomingDataSparkline);
|
process.stdout.write(artnetInSparkline);
|
||||||
process.stdout.write("\nOutgoing Data ")
|
process.stdout.write("\nArtNet Out\t")
|
||||||
process.stdout.write(sentDataSparkline);
|
process.stdout.write(artnetOutSparkline);
|
||||||
|
process.stdout.write("\nUSBDMX In\t")
|
||||||
|
process.stdout.write(usbdmxInSparkline);
|
||||||
|
process.stdout.write("\nUSBDMX Out\t")
|
||||||
|
process.stdout.write(usbdmxOutSparkline);
|
||||||
|
|
||||||
console.log("\n");
|
console.log("\n");
|
||||||
console.log(chalk.yellow(
|
console.log(chalk.yellow(
|
||||||
"Close the window or click Ctrl+C to terminate the program"
|
"Close the window or press Ctrl+C to terminate the program"
|
||||||
))
|
))
|
||||||
}
|
}
|
40
src/index.ts
40
src/index.ts
@ -4,21 +4,39 @@ import renderStartupScreen from "./startupscreen";
|
|||||||
import renderControlScreen from "./controlscreen";
|
import renderControlScreen from "./controlscreen";
|
||||||
import {clearInterval} from "timers";
|
import {clearInterval} from "timers";
|
||||||
import {exec} from "child_process";
|
import {exec} from "child_process";
|
||||||
|
import ConfigStorage from "./config/ConfigStorage";
|
||||||
|
|
||||||
|
import minimist from "minimist";
|
||||||
|
const argv = minimist(process.argv.slice(2));
|
||||||
|
|
||||||
export const defaultConvertHandler = new ConvertHandler();
|
export const defaultConvertHandler = new ConvertHandler();
|
||||||
|
export const defaultConfigStorage = new ConfigStorage();
|
||||||
let renderControlScreenTimer: NodeJS.Timeout;
|
let renderControlScreenTimer: NodeJS.Timeout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point of the program
|
* Entry point of the program
|
||||||
*/
|
*/
|
||||||
async function main() {
|
async function main() {
|
||||||
|
|
||||||
|
if (typeof argv["config"] === "string") {
|
||||||
|
defaultConfigStorage.loadConfig(argv["config"]);
|
||||||
|
}
|
||||||
|
|
||||||
setTerminalTitle("ArtNet => USBDMX")
|
setTerminalTitle("ArtNet => USBDMX")
|
||||||
const selectedInfo = await renderStartupScreen();
|
|
||||||
|
defaultConvertHandler.scanForInterfaces();
|
||||||
|
|
||||||
|
const selectedInfo = defaultConfigStorage.getInterface() ?? await renderStartupScreen();
|
||||||
|
|
||||||
|
if (argv._.includes("outputconfig")) {
|
||||||
|
console.log(JSON.stringify(selectedInfo, null, 2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
console.log(chalk.blueBright(
|
console.log(chalk.blueBright(
|
||||||
"Starting ArtNet..."
|
"Starting ArtNet..."
|
||||||
));
|
));
|
||||||
console.log(chalk.yellow(
|
console.log(chalk.yellow(
|
||||||
"Nimm bitte eventuell erscheinende Firewall-Hinweise an"
|
"Please accept any firewall requests"
|
||||||
))
|
))
|
||||||
defaultConvertHandler.startArtNetReceiver();
|
defaultConvertHandler.startArtNetReceiver();
|
||||||
|
|
||||||
@ -34,7 +52,7 @@ async function main() {
|
|||||||
openInterfaceResponse
|
openInterfaceResponse
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return process.exit(1);
|
throw "MissingInterfaceError"
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log(
|
console.log(
|
||||||
@ -42,7 +60,7 @@ async function main() {
|
|||||||
);
|
);
|
||||||
renderControlScreenTimer = setInterval(() => {
|
renderControlScreenTimer = setInterval(() => {
|
||||||
renderControlScreen();
|
renderControlScreen();
|
||||||
}, 1000);
|
}, 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,16 +91,24 @@ process.on('uncaughtException', (err) => {
|
|||||||
chalk.red(`⛔ A fatal error has occurred`)
|
chalk.red(`⛔ A fatal error has occurred`)
|
||||||
);
|
);
|
||||||
console.log(err);
|
console.log(err);
|
||||||
exec("pause press [enter]");
|
if (argv["autoretry"] === true) {
|
||||||
process.exit(0);
|
console.log("Auto-restart enabled, will restart now...")
|
||||||
|
setTimeout(() => {
|
||||||
|
main();
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
exec("pause press [enter]");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the title of the terminal
|
* Sets the title of the terminal
|
||||||
* @param title new title
|
* @param title new title
|
||||||
*/
|
*/
|
||||||
function setTerminalTitle(title: string){
|
function setTerminalTitle(title: string) {
|
||||||
process.stdout.write(
|
process.stdout.write(
|
||||||
String.fromCharCode(27) + "]0;" + title + String.fromCharCode(7)
|
String.fromCharCode(27) + "]0;" + title + String.fromCharCode(7)
|
||||||
);
|
);
|
||||||
|
@ -4,13 +4,14 @@ import figlet from "figlet";
|
|||||||
import inquirer from "inquirer";
|
import inquirer from "inquirer";
|
||||||
import {defaultConvertHandler} from "./index";
|
import {defaultConvertHandler} from "./index";
|
||||||
import modeToString from "./helpers/modeToString";
|
import modeToString from "./helpers/modeToString";
|
||||||
|
import {DetectedInterface} from "./usbdmx";
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const pjson = require('../package.json');
|
const pjson = require('../package.json');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data from the user selection about which interface to use
|
* Data from the user selection about which interface to use
|
||||||
*/
|
*/
|
||||||
interface StartupScreenResponse {
|
export interface StartupScreenResponse {
|
||||||
serial: string,
|
serial: string,
|
||||||
mode: string
|
mode: string
|
||||||
manufacturer: string | undefined,
|
manufacturer: string | undefined,
|
||||||
@ -25,7 +26,7 @@ export default async function renderStartupScreen(): Promise<StartupScreenRespon
|
|||||||
);
|
);
|
||||||
|
|
||||||
printCreditHeader();
|
printCreditHeader();
|
||||||
const scannedInterfaces = defaultConvertHandler.scanForInterfaces();
|
const scannedInterfaces: DetectedInterface[] = defaultConvertHandler.availableInterfaces;
|
||||||
|
|
||||||
const interfaceSelectionResponse = await inquirer.prompt(
|
const interfaceSelectionResponse = await inquirer.prompt(
|
||||||
[
|
[
|
||||||
|
@ -22,7 +22,8 @@ class DMXInterface {
|
|||||||
currentMode = 0;
|
currentMode = 0;
|
||||||
hidDevice: HID.HID;
|
hidDevice: HID.HID;
|
||||||
dmxout: number[];
|
dmxout: number[];
|
||||||
dataCallback: (value: DMXCommand) => void;
|
|
||||||
|
usbdmxInputCallback: (start: number, values: number[]) => void;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
path: string,
|
path: string,
|
||||||
@ -35,14 +36,16 @@ class DMXInterface {
|
|||||||
this.manufacturer = manufacturer;
|
this.manufacturer = manufacturer;
|
||||||
this.product = product;
|
this.product = product;
|
||||||
|
|
||||||
this.dataCallback = () => {};
|
|
||||||
this.hidDevice = new HID.HID(path);
|
this.hidDevice = new HID.HID(path);
|
||||||
this.hidDevice.on("data", (data: Buffer) => {
|
this.hidDevice.on("data", (data: Buffer) => {
|
||||||
// received buffer contains 33 bytes, the first one (data[0]) is the page and the rest are the dmx channel values
|
// received buffer contains 33 bytes, the first one (data[0]) is the page and the rest are the dmx channel values
|
||||||
// this means we get 32 dmx channels in one package
|
// this means we get 32 dmx channels in one package
|
||||||
|
|
||||||
|
const values: number[] = [];
|
||||||
for (let i = 1; i < 33; i++) {
|
for (let i = 1; i < 33; i++) {
|
||||||
this.dataCallback({channel: data[0] * 32 + i, value: data[i]});
|
values.push(data[i]);
|
||||||
}
|
}
|
||||||
|
this.usbdmxInputCallback(data[0] * 32, values);
|
||||||
|
|
||||||
})
|
})
|
||||||
this.dmxout = Array(512).fill(0);
|
this.dmxout = Array(512).fill(0);
|
||||||
|
@ -207,6 +207,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||||
|
|
||||||
|
"@types/minimist@^1.2.5":
|
||||||
|
version "1.2.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.5.tgz#ec10755e871497bcd83efe927e43ec46e8c0747e"
|
||||||
|
integrity sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==
|
||||||
|
|
||||||
"@types/node-hid@^1.3.4":
|
"@types/node-hid@^1.3.4":
|
||||||
version "1.3.4"
|
version "1.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node-hid/-/node-hid-1.3.4.tgz#adad8841dc0e05f988da287a91c64c75c554cfe0"
|
resolved "https://registry.yarnpkg.com/@types/node-hid/-/node-hid-1.3.4.tgz#adad8841dc0e05f988da287a91c64c75c554cfe0"
|
||||||
@ -1355,7 +1360,7 @@ minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion "^1.1.7"
|
brace-expansion "^1.1.7"
|
||||||
|
|
||||||
minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6:
|
minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6, minimist@^1.2.8:
|
||||||
version "1.2.8"
|
version "1.2.8"
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||||
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
||||||
|
Loading…
x
Reference in New Issue
Block a user