cbuslibrary
Version:
Library to decode & encode CBUS messages
1,078 lines (1,049 loc) • 266 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: cbuslibrary.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: cbuslibrary.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>'use strict';
/**
* @overview
* <strong>Module to decode & encode CBUS message strings</strong></br>
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// expects the 'raw' CBUS message in a modified form of the 'Grid connect' CAN over serial message syntax
//
// : <S | X> <IDENTIFIER> <N> <DATA-0> <DATA-1> … <DATA-7> ;
//
// The message starts at character position 0, with byte values being two hex characters
// For CBUS, an 11 bit CAN identifier is used, in 4 hex digits, character positions 2 to 5
// The CBUS data structure starts at character position 7
// The CBUS opCode is always character positions 7 & 8
// Any further CBUS data (dependant on opCode) starts at character character position 9
// For Extended (29) bit CAN identifier messages, the identifier is 8 hex digits, character positions 2 to 10
// the modification to standard 'grid connect' is the identifier (11 bit and 29 bit) is formatted to match PIC registers
// Two 8 bit registers for 11 bit, and four 8 bit registers for 29 bit
//
// All formats & naming conventions taken from CBUS specification
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function decToHex(num, len) {return parseInt(num & (2 ** (4*len) - 1)).toString(16).toUpperCase().padStart(len, '0');}
function stringToHex(string) {
// expects UTF-8 string
var bytes = new TextEncoder().encode(string);
return Array.from(
bytes,
byte => byte.toString(16).padStart(2, "0")
).join("");
}
function hexToString(hex) {
// returns UTF-8 string
const bytes = new Uint8Array(hex.length / 2);
for (let i = 0; i !== bytes.length; i++) {
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
}
return new TextDecoder().decode(bytes);
}
/**
*/
class cbusLibrary {
constructor() {
this.canHeader = {
'MjPri': 2, // lowest allowed priority (highest value)
'CAN_ID': 60,
}
}
//
// header() provides the prefix to add to CBUS data to compose a transmittable message
// CAN uses a bitwise arbitration scheme whereby the header with the lowest value has priority
// So higher values have lower priority
// It was origianlly believed that The CAN protocol prohibits a sequence of 7 or more 1 bits at the start of the header, so a
// MjPri. of 11 in binary (3 in decimal) is not used - HOWEVER, this has subsequently been shown not to be the case, so 3 can be used
//
header({
MjPri = this.canHeader.MjPri,
MinPri = 3,
CAN_ID = this.canHeader.CAN_ID
} = {}) {
// ensure all variables don't exceed the appropriate number of bits for encoding
// if (MjPri > 2) {MjPri = 2} // MjPri is two bits, but a value of 3 is not allowed **** no longer true ****
MjPri = MjPri % 4 // MjPri is two bits, 0 to 3
MinPri = MinPri % 4 // MinPri is two bits, 0 to 3
CAN_ID = CAN_ID % 128 // CAN_ID is 7 bits, 0 to 127
var identifier = parseInt(MjPri << 14) + parseInt(MinPri << 12) + parseInt(CAN_ID << 5)
return ':S' + decToHex(identifier, 4) + 'N'
}
/**
* gets the can header
* @return {String} Returns changeable CAN header parameters as JSON structure
* @example
* {
* 'MjPri': 2,
* 'CAN_ID': 60,
* }
*/
getCanHeader() {
return this.canHeader
}
/**
* setCanHeader
* @param {int} MjPri Major priority, two bit number 0 - 3 (3 is allowed, unlike previous assumption)
* @param {int} CAN_ID 7 bit number, 0 to 127
*/
setCanHeader(MjPri, CAN_ID) {
if (MjPri != undefined) {
this.canHeader.MjPri = (MjPri > 3) ? 3 : MjPri} // MjPri is two bits, but a value of 3 is n0t allowed
if (CAN_ID != undefined) { this.canHeader.CAN_ID = CAN_ID % 128} // CAN_ID is 7 bits, 0 to 127
}
//
//
// Decode / Encode Methods strictly arranged by numerical opcode to ensure that it's easy to spot if a function already exists
//
//
/**
* @desc Decode a CBUS message<br>
* This will decode both 11 bit ID CBUS messages and also 29 bit extended messages, as these are identified in the message itself <br>
* The actual CBUS messsage is expected to be in 'Grid connect' ASCII format, either as a plain string<br>
* or as the 'encoded' property in a JSON object<br>
* NOTE: doesn't preserve the original input JSON, but creates new JSON object as output
* @param {String} message CAN BUS message in a plain string or JSON format ('Grid connect' ASCII)
* @return {Object} Decoded properties as a JSON structure - content dependant on specific message,
* but will always have 'encoded' as the original input message, and also 'ID_TYPE' & 'text' elements<br>
* 'ID_TYPE' will be either 'S' (11 bit CBUS message) or 'X' (29 bit extended message) - or blank if not valid
*
* @example
*
* // 11 bit CBUS message
* {
* "encoded": ":SA780NE1FF00007F01FF01;",
* "ID_TYPE":"S",
* "mnemonic": "PLOC",
* "opCode": "E1",
* "session": 255,
* "address": 0,
* "speed": 127,
* "direction": "Reverse",
* "Fn1": 1,
* "Fn2": 255,
* "Fn3": 1,
* "text": "PLOC (E1) Session 255 Address 0 Speed/Dir 127 Direction Reverse Fn1 1 Fn2 255 Fn3 1"
* }
*
* // 29 bit firmware download control message
* {
* "encoded":":X00080004N000000000D040000;",
* "ID_TYPE":"X",
* "operation":"PUT",
* "type":"CONTROL",
* "address":"000000",
* "RESVD":0,
* "CTLBT":13,
* "SPCMD":4,
* "CPDTL":0,
* "CPDTH":0
* "text": {"encoded":":X00080004N000000000D040000;","ID_TYPE":"X","operation":"PUT","type":"CONTROL","address":"000000","RESVD":0,"CTLBT":13,"SPCMD":4,"CPDTL":0,"CPDTH":0}
* }
*/
decode(message) {
if(message.hasOwnProperty('encoded')) {
message = message.encoded;
}
if (( message.substr(1, 1) == 'S' ) & (message.length >= 9)) {
return this.decodeStandardMessage(message)
} else if (( message.substr(1, 1) == 'X' ) & (message.length >= 11)) {
return this.decodeExtendedMessage(message)
} else {
return {'encoded': message,
'ID_TYPE': '',
'text': 'Unsupported message',
}
}
}
decodeStandardMessage(message) {
if (message == undefined) message = this.message;
var opCode = message.substr(7, 2);
switch (opCode) {
case '00':
return this.decodeACK(message);
break;
case '01':
return this.decodeNAK(message);
break;
case '02':
return this.decodeHLT(message);
break;
case '03':
return this.decodeBON(message);
break;
case '04':
return this.decodeTOF(message);
break;
case '05':
return this.decodeTON(message);
break;
case '06':
return this.decodeESTOP(message);
break;
case '07':
return this.decodeARST(message);
break;
case '08':
return this.decodeRTOF(message);
break;
case '09':
return this.decodeRTON(message);
break;
case '0A':
return this.decodeRESTP(message);
break;
// 0B reserved
case '0C':
return this.decodeRSTAT(message);
break;
case '0D':
return this.decodeQNN(message);
break;
// 0E, 0F reserved
case '10':
return this.decodeRQNP(message);
break;
case '11':
return this.decodeRQMN(message);
break;
case '12':
return this.decodeGSTOP(message);
break;
// 13 - 20 reserved
case '21':
return this.decodeKLOC(message);
break;
case '22':
return this.decodeQLOC(message);
break;
case '23':
return this.decodeDKEEP(message);
break;
// 24 - 2F reserved
case '30':
return this.decodeDBG1(message);
break;
// 31 - 3E reserved
case '3F':
return this.decodeEXTC(message);
break;
case '40':
return this.decodeRLOC(message);
break;
case '41':
return this.decodeQCON(message);
break;
case '42':
return this.decodeSNN(message);
break;
case '43':
return this.decodeALOC(message);
break;
case '44':
return this.decodeSTMOD(message);
break;
case '45':
return this.decodePCON(message);
break;
case '46':
return this.decodeKCON(message);
break;
case '47':
return this.decodeDSPD(message);
break;
case '48':
return this.decodeDFLG(message);
break;
case '49':
return this.decodeDFNON(message);
break;
case '4A':
return this.decodeDFNOF(message);
break;
// 4B reserved
case '4C':
return this.decodeSSTAT(message);
break;
// 4D - 4E reserved
case '4F':
return this.decodeNNRSM(message);
break;
case '50':
return this.decodeRQNN(message);
break;
case '51':
return this.decodeNNREL(message);
break;
case '52':
return this.decodeNNACK(message);
break;
case '53':
return this.decodeNNLRN(message);
break;
case '54':
return this.decodeNNULN(message);
break;
case '55':
return this.decodeNNCLR(message);
break;
case '56':
return this.decodeNNEVN(message);
break;
case '57':
return this.decodeNERD(message);
break;
case '58':
return this.decodeRQEVN(message);
break;
case '59':
return this.decodeWRACK(message);
break;
case '5A':
return this.decodeRQDAT(message);
break;
case '5B':
return this.decodeRQDDS(message);
break;
case '5C':
return this.decodeBOOTM(message);
break;
case '5D':
return this.decodeENUM(message);
break;
// 5E reserved
case '5F':
return this.decodeEXTC1(message);
break;
case '60':
return this.decodeDFUN(message);
break;
case '61':
return this.decodeGLOC(message);
break;
// 62 - reserved
case '63':
return this.decodeERR(message);
break;
// 64 - 6E reserved
case '6F':
return this.decodeCMDERR(message);
break;
case '70':
return this.decodeEVNLF(message);
break;
case '71':
return this.decodeNVRD(message);
break;
case '72':
return this.decodeNENRD(message);
break;
case '73':
return this.decodeRQNPN(message);
break;
case '74':
return this.decodeNUMEV(message);
break;
case '75':
return this.decodeCANID(message);
break;
// 76 - 7E reserved
case '7F':
return this.decodeEXTC2(message);
break;
case '80':
return this.decodeRDCC3(message);
break;
// 81 - reserved
case '82':
return this.decodeWCVO(message);
break;
case '83':
return this.decodeWCVB(message);
break;
case '84':
return this.decodeQCVS(message);
break;
case '85':
return this.decodePCVS(message);
break;
// 86 - 8F reserved
case '90':
return this.decodeACON(message);
break;
case '91':
return this.decodeACOF(message);
break;
case '92':
return this.decodeAREQ(message);
break;
case '93':
return this.decodeARON(message);
break;
case '94':
return this.decodeAROF(message);
break;
case '95':
return this.decodeEVULN(message);
break;
case '96':
return this.decodeNVSET(message);
break;
case '97':
return this.decodeNVANS(message);
break;
case '98':
return this.decodeASON(message);
break;
case '99':
return this.decodeASOF(message);
break;
case '9A':
return this.decodeASRQ(message);
break;
case '9B':
return this.decodePARAN(message);
break;
case '9C':
return this.decodeREVAL(message);
break;
case '9D':
return this.decodeARSON(message);
break;
case '9E':
return this.decodeARSOF(message);
break;
case '9F':
return this.decodeEXTC3(message);
break;
case 'A0':
return this.decodeRDCC4(message);
break;
// A1 - reserved
case 'A2':
return this.decodeWCVS(message);
break;
// A3 - AA reserved
case 'AB':
return this.decodeHEARTB(message);
break;
// AC - AF reserved
case 'B0':
return this.decodeACON1(message);
break;
case 'B1':
return this.decodeACOF1(message);
break;
case 'B2':
return this.decodeREQEV(message);
break;
case 'B3':
return this.decodeARON1(message);
break;
case 'B4':
return this.decodeAROF1(message);
break;
case 'B5':
return this.decodeNEVAL(message);
break;
case 'B6':
return this.decodePNN(message);
break;
// B7 - reserved
case 'B8':
return this.decodeASON1(message);
break;
case 'B9':
return this.decodeASOF1(message);
break;
// BA - BC reserved
case 'BD':
return this.decodeARSON1(message);
break;
case 'BE':
return this.decodeARSOF1(message);
break;
case 'BF':
return this.decodeEXTC4(message);
break;
case 'C0':
return this.decodeRDCC5(message);
break;
case 'C1':
return this.decodeWCVOA(message);
break;
// C2 - CE reserved
case 'CF':
return this.decodeFCLK(message);
break;
case 'D0':
return this.decodeACON2(message);
break;
case 'D1':
return this.decodeACOF2(message);
break;
case 'D2':
return this.decodeEVLRN(message);
break;
case 'D3':
return this.decodeEVANS(message);
break;
case 'D4':
return this.decodeARON2(message);
break;
case 'D5':
return this.decodeAROF2(message);
break;
// D6 - D7 reserved
case 'D8':
return this.decodeASON2(message);
break;
case 'D9':
return this.decodeASOF2(message);
break;
// DA - DC reserved
case 'DD':
return this.decodeARSON2(message);
break;
case 'DE':
return this.decodeARSOF2(message);
break;
case 'DF':
return this.decodeEXTC5(message);
break;
case 'E0':
return this.decodeRDCC6(message);
break;
case 'E1':
return this.decodePLOC(message);
break;
case 'E2':
return this.decodeNAME(message);
break;
case 'E3':
return this.decodeSTAT(message);
break;
// E4 - EE reserved
case 'F0':
return this.decodeACON3(message);
break;
case 'EF':
return this.decodePARAMS(message);
break;
case 'F0':
return this.decodeACON3(message);
break;
case 'F1':
return this.decodeACOF3(message);
break;
case 'F2':
return this.decodeENRSP(message);
break;
case 'F3':
return this.decodeARON3(message);
break;
case 'F4':
return this.decodeAROF3(message);
break;
case 'F5':
return this.decodeEVLRNI(message);
break;
case 'F6':
return this.decodeACDAT(message);
break;
case 'F7':
return this.decodeARDAT(message);
break;
case 'F8':
return this.decodeASON3(message);
break;
case 'F9':
return this.decodeASOF3(message);
break;
case 'FA':
return this.decodeDDES(message);
break;
case 'FB':
return this.decodeDDRS(message);
break;
// FC - reserved
case 'FD':
return this.decodeARSON3(message);
break;
case 'FE':
return this.decodeARSOF3(message);
break;
case 'FF':
return this.decodeEXTC6(message);
break;
default:
return {'encoded': message, 'ID_TYPE': 'S', 'mnemonic': 'UNSUPPORTED', 'opCode': message.substr(7, 2), 'text': 'UNSUPPORTED (' + message.substr(7, 2) + ')'}
break;
}
}
decodeExtendedMessage(message) {
var output = {}
output['encoded'] = message
output['ID_TYPE'] = 'X'
if ((message.length >= 27) & (message.substr(0,9) == ':X0008000')){
if(parseInt(message.substr(9,1), 16) & 0b0010) {
output['operation'] = 'GET'
} else {
output['operation'] = 'PUT'
}
if(parseInt(message.substr(9,1), 16) & 0b0001) {
output['type'] = 'DATA'
var data = []
data.push(parseInt(message.substr(11, 2), 16))
data.push(parseInt(message.substr(13, 2), 16))
data.push(parseInt(message.substr(15, 2), 16))
data.push(parseInt(message.substr(17, 2), 16))
data.push(parseInt(message.substr(19, 2), 16))
data.push(parseInt(message.substr(21, 2), 16))
data.push(parseInt(message.substr(23, 2), 16))
data.push(parseInt(message.substr(25, 2), 16))
output['data'] = data
output['text'] = JSON.stringify(output)
} else {
output['type'] = 'CONTROL'
output['address'] = message.substr(15, 2) + message.substr(13, 2) + message.substr(11, 2)
output['RESVD'] = parseInt(message.substr(17, 2), 16)
output['CTLBT'] = parseInt(message.substr(19, 2), 16)
output['SPCMD'] = parseInt(message.substr(21, 2), 16)
output['CPDTL'] = parseInt(message.substr(23, 2), 16)
output['CPDTH'] = parseInt(message.substr(25, 2), 16)
output['text'] = JSON.stringify(output)
}
} else if (message.length >= 13) {
output['operation'] = 'RESPONSE'
output['response'] = parseInt(message.substr(11, 2), 16)
output['text'] = JSON.stringify(output)
} else {
output['Type'] = 'UNKNOWN MESSAGE'
output['text'] = JSON.stringify(output)
}
return output
}
/**
* @desc encode a CBUS message<br>
* This will encode either a 11 bit 'standard' or 29 bit 'extended' ID CBUS message from a supplied JSON object into a 'grid connect' ascii format<br>
* If the correct JSON properties for the parameters for the encoding are not present, an exception will be thrown<br>
* The JSON properties shared by both encode() & decode() are identical - however note decode() may return more properties than encode() requires<br>
* @param {Object} message - CBUS message properties as a JSON object
* @return {Object} returns the original input JSON object with the resultant encoded CBUS message added using the 'encoded' property
*
*/
encode(message){
if(message.hasOwnProperty('ID_TYPE')) {
switch (message['ID_TYPE']) {
case 'S':
return this.encodeStandardMessage(message);
break;
case 'X':
return this.encodeExtendedMessage(message);
break;
default:
throw Error('encode: ID_TYPE ' + message.ID_TYPE + ' not supported');
break;
}
}
else{
// assume its a standard message if no ID type supplied, so check if 'mnemonic' present
if(message.hasOwnProperty('mnemonic')) {
return this.encodeStandardMessage(message);
}
else {
throw Error('encode: unable to determine message type - no ID_TYPE present');
}
}
}
/**
* @desc encode a standard CBUS message<br>
* This will encode a 11 bit ID CBUS message from a supplied JSON object into a 'grid connect' ascii format<br>
* The supplied JSON must include the mnemonic for the opcode, and any necessary parameters for that specific opcode<br>
* If the correct JSON properties for the parameters for the opcode are not present, an exception will be thrown<br>
* The JSON properties shared by both encode() & decode() are identical - however note decode() may return more properties than encode() requires<br>
* @param {Object} message - CBUS message properties as a JSON object - content dependant on specific CBUS opcode, but must always contain 'mnemonic'
* @return {Object} returns the original input JSON object with the resultant encoded CBUS message added using the 'encoded' property
*
*/
encodeStandardMessage(message){
if(message.hasOwnProperty('mnemonic')) {
switch (message.mnemonic) {
case 'ACK': // 00
message.encoded = this.encodeACK();
break;
case 'NAK': // 01
message.encoded = this.encodeNAK();
break;
case 'HLT': // 02
message.encoded = this.encodeHLT();
break;
case 'BON': // 03
message.encoded = this.encodeBON();
break;
case 'TOF': // 04
message.encoded = this.encodeTOF();
break;
case 'TON': // 05
message.encoded = this.encodeTON();
break;
case 'ESTOP': // 06
message.encoded = this.encodeESTOP();
break;
case 'ARST': // 07
message.encoded = this.encodeARST();
break;
case 'RTOF': // 08
message.encoded = this.encodeRTOF();
break;
case 'RTON': // 09
message.encoded = this.encodeRTON();
break;
case 'RESTP': // 0A
message.encoded = this.encodeRESTP();
break;
case 'RSTAT': // 0C
message.encoded = this.encodeRSTAT();
break;
case 'QNN': // 0D
message.encoded = this.encodeQNN();
break;
case 'RQNP': // 10
message.encoded = this.encodeRQNP();
break;
case 'RQMN': // 11
message.encoded = this.encodeRQMN();
break;
case 'GSTOP': // 12
message.encoded = this.encodeGSTOP();
break;
case 'KLOC': // 21
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
message.encoded = this.encodeKLOC(message.session);
break;
case 'QLOC': // 22
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
message.encoded = this.encodeQLOC(message.session);
break;
case 'DKEEP': // 23
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
message.encoded = this.encodeDKEEP(message.session);
break;
case 'DBG1': // 30
if(!message.hasOwnProperty('status')) {throw Error("encode: property 'status' missing")};
message.encoded = this.encodeDBG1(message.status);
break;
case 'EXTC': // 3F
if(!message.hasOwnProperty('Ext_OPC')) {throw Error("encode: property 'Ext_OPC' missing")};
message.encoded = this.encodeEXTC(message.Ext_OPC);
break;
case 'RLOC': // 40
if(!message.hasOwnProperty('address')) {throw Error("encode: property 'address' missing")};
message.encoded = this.encodeRLOC(message.address);
break;
case 'QCON': // 41
if(!message.hasOwnProperty('conID')) {throw Error("encode: property 'conID' missing")};
if(!message.hasOwnProperty('index')) {throw Error("encode: property 'index' missing")};
message.encoded = this.encodeQCON(message.conID, message.index);
break;
case 'SNN': // 42
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeSNN(message.nodeNumber);
break;
case 'ALOC': // 43
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('allocationCode')) {throw Error("encode: property 'allocationCode' missing")};
message.encoded = this.encodeALOC(message.session, message.allocationCode);
break;
case 'STMOD': // 44
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('modeByte')) {throw Error("encode: property 'modeByte' missing")};
message.encoded = this.encodeSTMOD(message.session, message.modeByte);
break;
case 'PCON': // 45
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('consistAddress')) {throw Error("encode: property 'consistAddress' missing")};
message.encoded = this.encodePCON(message.session, message.consistAddress);
break;
case 'KCON': // 46
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('consistAddress')) {throw Error("encode: property 'consistAddress' missing")};
message.encoded = this.encodeKCON(message.session, message.consistAddress);
break;
case 'DSPD': // 47
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('speed')) {throw Error("encode: property 'speed' missing")};
if(!message.hasOwnProperty('direction')) {throw Error("encode: property 'direction' missing")};
message.encoded = this.encodeDSPD(message.session, message.speed, message.direction);
break;
case 'DFLG': // 48
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('flags')) {throw Error("encode: property 'flags' missing")};
message.encoded = this.encodeDFLG(message.session, message.flags);
break;
case 'DFNON': // 49
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('functionNumber')) {throw Error("encode: property 'functionNumber' missing")};
message.encoded = this.encodeDFNON(message.session, message.functionNumber);
break;
case 'DFNOF': // 4A
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('functionNumber')) {throw Error("encode: property 'functionNumber' missing")};
message.encoded = this.encodeDFNOF(message.session, message.functionNumber);
break;
case 'SSTAT': // 4C
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('status')) {throw Error("encode: property 'status' missing")};
message.encoded = this.encodeSSTAT(message.session, message.status);
break;
case 'NNRSM': // 4F
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeNNRSM(message.nodeNumber);
break;
case 'RQNN': // 50
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeRQNN(message.nodeNumber);
break;
case 'NNREL': // 51
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeNNREL(message.nodeNumber);
break;
case 'NNACK': // 52
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeNNACK(message.nodeNumber);
break;
case 'NNLRN': // 53
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeNNLRN(message.nodeNumber);
break;
case 'NNULN': // 54
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeNNULN(message.nodeNumber);
break;
case 'NNCLR': // 55
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeNNCLR(message.nodeNumber, message.status);
break;
case 'NNEVN': // 56
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeNNEVN(message.nodeNumber);
break;
case 'NERD': // 57
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeNERD(message.nodeNumber);
break;
case 'RQEVN': // 58
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeRQEVN(message.nodeNumber);
break;
case 'WRACK': // 59
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeWRACK(message.nodeNumber);
break;
case 'RQDAT': // 5A
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeRQDAT(message.nodeNumber);
break;
case 'RQDDS': // 5B
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeRQDDS(message.nodeNumber);
break;
case 'BOOTM': // 5C
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeBOOTM(message.nodeNumber);
break;
case 'ENUM': // 5D
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
message.encoded = this.encodeENUM(message.nodeNumber);
break;
case 'EXTC1': // 5F
if(!message.hasOwnProperty('Ext_OPC')) {throw Error("encode: property 'Ext_OPC' missing")};
if(!message.hasOwnProperty('byte1')) {throw Error("encode: property 'byte1' missing")};
message.encoded = this.encodeEXTC1(message.Ext_OPC, message.byte1);
break;
case 'DFUN': // 60
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('Fn1')) {throw Error("encode: property 'Fn1' missing")};
if(!message.hasOwnProperty('Fn2')) {throw Error("encode: property 'Fn2' missing")};
message.encoded = this.encodeDFUN(message.session, message.Fn1, message.Fn2);
break;
case 'GLOC': // 61
if(!message.hasOwnProperty('address')) {throw Error("encode: property 'address' missing")};
if(!message.hasOwnProperty('flags')) {throw Error("encode: property 'flags' missing")};
message.encoded = this.encodeGLOC(message.address, message.flags);
break;
case 'ERR': // 63
if(!message.hasOwnProperty('data1')) {throw Error("encode: property 'data1' missing")};
if(!message.hasOwnProperty('data2')) {throw Error("encode: property 'data2' missing")};
if(!message.hasOwnProperty('errorNumber')) {throw Error("encode: property 'errorNumber' missing")};
message.encoded = this.encodeERR(message.data1, message.data2, message.errorNumber);
break;
case 'CMDERR': // 6F
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('errorNumber')) {throw Error("encode: property 'errorNumber' missing")};
message.encoded = this.encodeCMDERR(message.nodeNumber, message.errorNumber);
break;
case 'EVNLF': // 70
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('EVSPC')) {throw Error("encode: property 'EVSPC' missing")};
message.encoded = this.encodeEVNLF(message.nodeNumber, message.EVSPC);
break;
case 'NVRD': // 71
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('nodeVariableIndex')) {throw Error("encode: property 'nodeVariableIndex' missing")};
message.encoded = this.encodeNVRD(message.nodeNumber, message.nodeVariableIndex);
break;
case 'NENRD': // 72
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('eventIndex')) {throw Error("encode: property 'eventIndex' missing")};
message.encoded = this.encodeNENRD(message.nodeNumber, message.eventIndex);
break;
case 'RQNPN': // 73
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('parameterIndex')) {throw Error("encode: property 'parameterIndex' missing")};
message.encoded = this.encodeRQNPN(message.nodeNumber, message.parameterIndex);
break;
case 'NUMEV': // 74
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('eventCount')) {throw Error("encode: property 'eventCount' missing")};
message.encoded = this.encodeNUMEV(message.nodeNumber, message.eventCount);
break;
case 'CANID': // 75
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('CAN_ID')) {throw Error("encode: property 'CAN_ID' missing")};
message.encoded = this.encodeCANID(message.nodeNumber, message.CAN_ID);
break;
case 'EXTC2': // 7F
if(!message.hasOwnProperty('Ext_OPC')) {throw Error("encode: property 'Ext_OPC' missing")};
if(!message.hasOwnProperty('byte1')) {throw Error("encode: property 'byte1' missing")};
if(!message.hasOwnProperty('byte2')) {throw Error("encode: property 'byte2' missing")};
message.encoded = this.encodeEXTC2(message.Ext_OPC, message.byte1, message.byte2);
break;
case 'RDCC3': // 80
if(!message.hasOwnProperty('repetitions')) {throw Error("encode: property 'repetitions' missing")};
if(!message.hasOwnProperty('byte0')) {throw Error("encode: property 'byte0' missing")};
if(!message.hasOwnProperty('byte1')) {throw Error("encode: property 'byte1' missing")};
if(!message.hasOwnProperty('byte2')) {throw Error("encode: property 'byte2' missing")};
message.encoded = this.encodeRDCC3(message.repetitions, message.byte0, message.byte1, message.byte2);
break;
case 'WCVO': // 82
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('CV')) {throw Error("encode: property 'CV' missing")};
if(!message.hasOwnProperty('value')) {throw Error("encode: property 'value' missing")};
message.encoded = this.encodeWCVO(message.session, message.CV, message.value);
break;
case 'WCVB': // 83
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('CV')) {throw Error("encode: property 'CV' missing")};
if(!message.hasOwnProperty('value')) {throw Error("encode: property 'value' missing")};
message.encoded = this.encodeWCVB(message.session, message.CV, message.value);
break;
case 'QCVS': // 84
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('CV')) {throw Error("encode: property 'CV' missing")};
if(!message.hasOwnProperty('mode')) {throw Error("encode: property 'mode' missing")};
message.encoded = this.encodeQCVS(message.session, message.CV, message.mode);
break;
case 'PCVS': // 85
if(!message.hasOwnProperty('session')) {throw Error("encode: property 'session' missing")};
if(!message.hasOwnProperty('CV')) {throw Error("encode: property 'CV' missing")};
if(!message.hasOwnProperty('value')) {throw Error("encode: property 'value' missing")};
message.encoded = this.encodePCVS(message.session, message.CV, message.value);
break;
case 'ACON': // 90
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('eventNumber')) {throw Error("encode: property 'eventNumber' missing")};
message.encoded = this.encodeACON(message.nodeNumber, message.eventNumber);
break;
case 'ACOF': // 91
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('eventNumber')) {throw Error("encode: property 'eventNumber' missing")};
message.encoded = this.encodeACOF(message.nodeNumber, message.eventNumber);
break;
case 'AREQ': // 92
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('eventNumber')) {throw Error("encode: property 'eventNumber' missing")};
message.encoded = this.encodeAREQ(message.nodeNumber, message.eventNumber);
break;
case 'ARON': // 93
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('eventNumber')) {throw Error("encode: property 'eventNumber' missing")};
message.encoded = this.encodeARON(message.nodeNumber, message.eventNumber);
break;
case 'AROF': // 94
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('eventNumber')) {throw Error("encode: property 'eventNumber' missing")};
message.encoded = this.encodeAROF(message.nodeNumber, message.eventNumber);
break;
case 'EVULN': // 95
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('eventNumber')) {throw Error("encode: property 'eventNumber' missing")};
message.encoded = this.encodeEVULN(message.nodeNumber, message.eventNumber);
break;
case 'NVSET': // 96
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('nodeVariableIndex')) {throw Error("encode: property 'nodeVariableIndex' missing")};
if(!message.hasOwnProperty('nodeVariableValue')) {throw Error("encode: property 'nodeVariableValue' missing")};
message.encoded = this.encodeNVSET(message.nodeNumber, message.nodeVariableIndex, message.nodeVariableValue);
break;
case 'NVANS': // 97
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('nodeVariableIndex')) {throw Error("encode: property 'nodeVariableIndex' missing")};
if(!message.hasOwnProperty('nodeVariableValue')) {throw Error("encode: property 'nodeVariableValue' missing")};
message.encoded = this.encodeNVANS(message.nodeNumber, message.nodeVariableIndex, message.nodeVariableValue);
break;
case 'ASON': // 98
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('deviceNumber')) {throw Error("encode: property 'deviceNumber' missing")};
message.encoded = this.encodeASON(message.nodeNumber, message.deviceNumber);
break;
case 'ASOF': // 99
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('deviceNumber')) {throw Error("encode: property 'deviceNumber' missing")};
message.encoded = this.encodeASOF(message.nodeNumber, message.deviceNumber);
break;
case 'ASRQ': // 9A
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('deviceNumber')) {throw Error("encode: property 'deviceNumber' missing")};
message.encoded = this.encodeASRQ(message.nodeNumber, message.deviceNumber);
break;
case 'PARAN': // 9B
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('parameterIndex')) {throw Error("encode: property 'parameterIndex' missing")};
if(!message.hasOwnProperty('parameterValue')) {throw Error("encode: property 'parameterValue' missing")};
message.encoded = this.encodePARAN(message.nodeNumber, message.parameterIndex, message.parameterValue);
break;
case 'REVAL': // 9C
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('eventIndex')) {throw Error("encode: property 'eventIndex' missing")};
if(!message.hasOwnProperty('eventVariableIndex')) {throw Error("encode: property 'eventVariableIndex' missing")};
message.encoded = this.encodeREVAL(message.nodeNumber, message.eventIndex, message.eventVariableIndex);
break;
case 'ARSON': // 9D
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('deviceNumber')) {throw Error("encode: property 'deviceNumber' missing")};
message.encoded = this.encodeARSON(message.nodeNumber, message.deviceNumber);
break;
case 'ARSOF': // 9E
if(!message.hasOwnProperty('nodeNumber')) {throw Error("encode: property 'nodeNumber' missing")};
if(!message.hasOwnProperty('deviceNumber')) {throw Error("encode: property 'deviceNumber' missing")};
message.encoded = this.encodeARSOF(message.nodeNumber, message.deviceNumber);
break;
case 'EXTC3': // 9F
if(!message.hasOwnProperty('Ext_OPC')) {throw Error("encode: property 'Ext_OPC' missing")};
if(!message.hasOwnProperty('byte1')) {throw Error("encode: property 'byte1' missing")};
if(!message.hasOwnProperty('byte2'))