2023-10-08 18:44:10 +02:00
|
|
|
import {dmxnet, receiver} from "dmxnet";
|
|
|
|
import {DetectedInterface, DMXInterface, getConnectedInterfaces} from "./usbdmx";
|
|
|
|
import {clearInterval} from "timers";
|
|
|
|
|
2024-01-29 22:18:20 +01:00
|
|
|
/**
|
|
|
|
* Responsible for converting incoming Art-Net data to an USBDMX output
|
|
|
|
*/
|
2023-10-08 18:44:10 +02:00
|
|
|
export default class ConvertHandler {
|
|
|
|
dmxnetManager: dmxnet;
|
|
|
|
artNetReceiver: receiver;
|
|
|
|
|
|
|
|
recentDMXArray: number[] = Array(512).fill(0);
|
|
|
|
|
|
|
|
availableInterfaces: DetectedInterface[] = [];
|
|
|
|
|
|
|
|
dmxInterface: DMXInterface | undefined;
|
|
|
|
outputAllowed = false;
|
|
|
|
|
|
|
|
incomingDataCounter = 0;
|
|
|
|
sentDataCounter = 0;
|
|
|
|
dataPerSecTimer: NodeJS.Timeout;
|
|
|
|
incomingDataHistory: number[] = [];
|
|
|
|
sentDataHistory: number[] = [];
|
|
|
|
|
2024-01-29 22:18:20 +01:00
|
|
|
/**
|
|
|
|
* Starts up the Art-Net receiver
|
|
|
|
*/
|
2023-10-08 18:44:10 +02:00
|
|
|
startArtNetReceiver = () => {
|
|
|
|
this.dmxnetManager = new dmxnet({
|
|
|
|
log: {level: "error"}
|
|
|
|
});
|
|
|
|
this.artNetReceiver = this.dmxnetManager.newReceiver();
|
|
|
|
this.artNetReceiver.on("data", this.handleIncomingArtNetData);
|
|
|
|
}
|
|
|
|
|
2024-01-29 22:18:20 +01:00
|
|
|
/**
|
|
|
|
* Handles incoming Art-Net dara and writes it to the DMX interface
|
|
|
|
* @param data Art-Net data
|
|
|
|
*/
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
2023-10-08 18:44:10 +02:00
|
|
|
handleIncomingArtNetData = (data: any) => {
|
|
|
|
this.incomingDataCounter++;
|
|
|
|
if (JSON.stringify(data) != JSON.stringify(this.recentDMXArray)) {
|
|
|
|
if (this.dmxInterface && this.outputAllowed) {
|
|
|
|
this.sentDataCounter++;
|
|
|
|
this.dmxInterface.writeMap(data);
|
|
|
|
}
|
|
|
|
this.recentDMXArray = data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-29 22:18:20 +01:00
|
|
|
/**
|
|
|
|
* Gets available DMX interfaces connected to the computer
|
|
|
|
*/
|
2023-10-08 18:44:10 +02:00
|
|
|
scanForInterfaces = (): DetectedInterface[] => {
|
|
|
|
this.availableInterfaces = getConnectedInterfaces();
|
|
|
|
return this.availableInterfaces;
|
|
|
|
}
|
|
|
|
|
2024-01-29 22:18:20 +01:00
|
|
|
/**
|
|
|
|
* Tries to open the connection to a DMX interface
|
|
|
|
* @param serial Serial number of the interface
|
|
|
|
* @param mode Operating mode
|
|
|
|
* @param manufacturer Interface manufacturer ID
|
|
|
|
* @param product Interface product ID
|
|
|
|
* @returns an empty string if the connection was successful or the error message
|
|
|
|
*/
|
2023-10-08 18:44:10 +02:00
|
|
|
openInterface = async (serial: string, mode: string, manufacturer: string | undefined = undefined, product: string | undefined = undefined): Promise<string> => {
|
|
|
|
if (isNaN(parseInt(mode))) return "Invalid mode";
|
|
|
|
|
|
|
|
const interfaceIndex = this.availableInterfaces.findIndex((e) => e.serial == serial);
|
2024-01-29 22:18:20 +01:00
|
|
|
if (interfaceIndex === -1) return "Interface not found, please scan again";
|
|
|
|
|
2023-10-08 18:44:10 +02:00
|
|
|
const interfacePath = this.availableInterfaces[interfaceIndex].path;
|
2024-01-29 22:18:20 +01:00
|
|
|
|
2023-10-08 18:44:10 +02:00
|
|
|
try {
|
|
|
|
this.dmxInterface = await DMXInterface.open(interfacePath, serial, manufacturer, product);
|
|
|
|
return new Promise<string>((resolve) => {
|
|
|
|
setTimeout( () => {
|
2024-01-29 22:18:20 +01:00
|
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
|
|
// @ts-expect-error
|
2023-10-08 18:44:10 +02:00
|
|
|
const response = this.dmxInterface.setMode(parseInt(mode));
|
|
|
|
this.outputAllowed = true;
|
|
|
|
this.dataPerSecTimer = setInterval(this.parseRequestTimer, 1000);
|
2024-01-29 22:18:20 +01:00
|
|
|
resolve(response === 0 ? "" : `Error Code ${response}`);
|
2023-10-08 18:44:10 +02:00
|
|
|
}, 1000);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
catch(err) {
|
|
|
|
console.log(err);
|
|
|
|
return (err as Error).message;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-29 22:18:20 +01:00
|
|
|
/**
|
|
|
|
* Closes the connection to a DMX interface
|
|
|
|
*/
|
2023-10-08 18:44:10 +02:00
|
|
|
closeInterface = () => {
|
|
|
|
if (this.dmxInterface) {
|
|
|
|
this.dmxInterface.close();
|
|
|
|
this.outputAllowed = false;
|
|
|
|
clearInterval(this.dataPerSecTimer);
|
|
|
|
this.dmxInterface = undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-29 22:18:20 +01:00
|
|
|
/**
|
|
|
|
* Processes incoming and sent data history for visualization
|
|
|
|
*/
|
2023-10-08 18:44:10 +02:00
|
|
|
parseRequestTimer = () => {
|
|
|
|
this.incomingDataHistory.push(this.incomingDataCounter);
|
|
|
|
if (this.incomingDataHistory.length > 20) {
|
|
|
|
this.incomingDataHistory = this.incomingDataHistory.slice(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
this.sentDataHistory.push(this.sentDataCounter);
|
|
|
|
if (this.sentDataHistory.length > 20) {
|
|
|
|
this.sentDataHistory = this.sentDataHistory.slice(1)
|
|
|
|
}
|
|
|
|
this.incomingDataCounter = 0;
|
|
|
|
this.sentDataCounter = 0;
|
|
|
|
}
|
|
|
|
}
|