Files
django-ram/ram/driver/static/wt/js/emulator.js

222 lines
5.2 KiB
JavaScript

/* 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 RestAPI {
constructor({logger}) {
this.csrftoken = this.getCookie('csrftoken');
this.logger = logger
}
getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
write(packet) {
$.ajax({
type: "PUT",
url: "/api/v1/dcc/command",
data: packet,
success: function (data) { displayLog('[RECEIVE] '+data.response.replace(/\n/g,"")); },
contentType: "text/plain",
headers: {'X-CSRFToken': this.csrftoken}
});
}
}
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
}
}