UNPKG

cbuslibrary

Version:

Library to decode & encode CBUS messages

1,078 lines (1,049 loc) 266 kB
<!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 * &lt;strong>Module to decode &amp; encode CBUS message strings&lt;/strong>&lt;/br> */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // expects the 'raw' CBUS message in a modified form of the 'Grid connect' CAN over serial message syntax // // : &lt;S | X> &lt;IDENTIFIER> &lt;N> &lt;DATA-0> &lt;DATA-1> … &lt;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 &amp; 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 &amp; naming conventions taken from CBUS specification //////////////////////////////////////////////////////////////////////////////////////////////////////////////// function decToHex(num, len) {return parseInt(num &amp; (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 &lt;&lt; 14) + parseInt(MinPri &lt;&lt; 12) + parseInt(CAN_ID &lt;&lt; 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&lt;br> * This will decode both 11 bit ID CBUS messages and also 29 bit extended messages, as these are identified in the message itself &lt;br> * The actual CBUS messsage is expected to be in 'Grid connect' ASCII format, either as a plain string&lt;br> * or as the 'encoded' property in a JSON object&lt;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' &amp; 'text' elements&lt;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' ) &amp; (message.length >= 9)) { return this.decodeStandardMessage(message) } else if (( message.substr(1, 1) == 'X' ) &amp; (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) &amp; (message.substr(0,9) == ':X0008000')){ if(parseInt(message.substr(9,1), 16) &amp; 0b0010) { output['operation'] = 'GET' } else { output['operation'] = 'PUT' } if(parseInt(message.substr(9,1), 16) &amp; 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&lt;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&lt;br> * If the correct JSON properties for the parameters for the encoding are not present, an exception will be thrown&lt;br> * The JSON properties shared by both encode() &amp; decode() are identical - however note decode() may return more properties than encode() requires&lt;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&lt;br> * This will encode a 11 bit ID CBUS message from a supplied JSON object into a 'grid connect' ascii format&lt;br> * The supplied JSON must include the mnemonic for the opcode, and any necessary parameters for that specific opcode&lt;br> * If the correct JSON properties for the parameters for the opcode are not present, an exception will be thrown&lt;br> * The JSON properties shared by both encode() &amp; decode() are identical - however note decode() may return more properties than encode() requires&lt;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'))