Import WebThrottle-EX from ca33f6a

This commit is contained in:
2022-04-22 00:04:50 +02:00
parent dc85f62577
commit 4de6f83f3f
41 changed files with 7015 additions and 0 deletions

View File

@@ -0,0 +1,187 @@
/* This is part of the DCC++ EX Project for model railroading and more.
For licence information, please see index.html.
For more information, see us at dcc-ex.com.
emulator.js
Allows the software to operate without a Command Station attached. This
file manages the correct response that a Command Station would provide.
*/
/**
* Utility function can be moved when we can import files
* @description Removes control characters "<", ">" and "\n"
* @param {string} packet
* @return {string}
*/
function removeControlCharacters(packet) {
return [...packet].filter(char => !["<", ">", "\n"].includes(char)).join("")
}
/**
* Utility function can be moved when we can import files
* @description Finds the first non-blank character after control characters are removed
* @param {string} packet
* @return {string}
*/
function extractPacketKey(packet) {
const cleanedPacket = [...removeControlCharacters(packet)]
return cleanedPacket.find(char => char !== " ");
}
class Emulator {
constructor({logger}) {
this.turnoutEmulator = new TurnoutEmulator()
this.logger = logger
}
/**
* @param {string} packet
*/
write(packet) {
if (packet === "<credits>") {
console.log("Credits")
return credits()
}
let packetKey = extractPacketKey(packet);
switch (packetKey) {
// Cab control
case ("t"):
this.logger('[RECEIVE] '+ this.#cabControlCommand(packet))
break;
// Track power off
case ('0') :
this.logger('[RECEIVE] '+ this.#powerOffCommand(packet));
break;
// Track power on
case ('1'):
this.logger('[RECEIVE] '+ this.#powerOnCommand(packet));
break;
// New cab functions
case ('F'):
this.logger('[RECEIVE] '+ this.#cabFunctionCommand(packet));
break;
// Legacy cab functions
case ('f'):
this.logger('[RECEIVE] '+ this.#cabFunctionCommand(packet, true));
break;
// Turnouts
case ('T'): //Not fully finished
this.logger('[RECEIVE] '+ this.#turnoutCommand(packet, this.turnoutEmulator))
break
default:
break;
}
}
/**
* @param {string} packet
* @return {string}
*/
#cabControlCommand(packet) {
const splitPacket = packet.split(" ");
return 'T 1 ' + splitPacket[3] + ' ' + splitPacket[4].substring(0, splitPacket[4].length - 2);
}
/**
* @param {string} packet
* @return {string}
*/
#powerOffCommand(packet) {
return 'p0';
}
/**
* @param {string} packet
* @return {string}
*/
#powerOnCommand(packet) {
return 'p1';
}
/**
* @param {string} packet
* @param {boolean} legacy
* @return number
*/
#cabFunctionCommand(packet, legacy = false) {
return NaN;
}
/**
* @param {string} packet
* @param {TurnoutEmulator} turnoutEmulator
* @return {string}
*/
#turnoutCommand(packet, turnoutEmulator = new TurnoutEmulator()) {
const splitPacket = removeControlCharacters(packet).split(" ");
if (splitPacket.length === 4) {
// Adds a Turnout
return turnoutEmulator.addTurnout(new Turnout(packet))
} else if (splitPacket.length === 2) {
// Removes a Turnout
return turnoutEmulator.removeTurnout(splitPacket[1])
} else if (splitPacket.length === 1) {
// Reads Turnouts
return turnoutEmulator.turnouts
}
}
}
class TurnoutEmulator {
/**
* @type {[]}
*/
#turnouts = []
/**
* @return {string|string[]}
*/
get turnouts() {
if (!this.#turnouts.length) {
return 'X'
}
return this.#turnouts.map(turnout => `H ${turnout.id} ${turnout.address} ${turnout.subaddress} ${turnout.thrown}`)
}
/**
* @param {*} turnout
* @return {string}
*/
addTurnout(turnout) {
this.#turnouts = [...this.#turnouts, turnout]
console.log(this.#turnouts);
return '<O>';
}
/**
* @param {string} turnoutId
* @return {string}
*/
removeTurnout(turnoutId) {
this.#turnouts = this.#turnouts.filter(turnout => turnout.id !== turnoutId);
console.log(this.#turnouts);
return 'O';
}
}
class Turnout {
constructor(packet) {
let [_key, id, address, subaddress] = removeControlCharacters(packet).split(" ");
this.id = id
this.address = address
this.subaddress = subaddress
this.thrown = 0
}
}