PyVLCB 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyVLCB
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: A library for CBUS / VLCB communication
5
5
  Author-email: "Stewart Watkiss (penguintutor)" <5587863+penguintutor@users.noreply.github.com>
6
6
  License: MIT License
@@ -101,6 +101,7 @@ Example code is stored within the demo folder available on GitHub. Copy these in
101
101
 
102
102
  * The demos are created for a Raspberry Pi or other Linux computers.
103
103
  * The USB port is hard-coded as /dev/ttyACM0.
104
+ * The Loco ID is hard-coded as 3.
104
105
  * For other computers or USB ports, edit the Python file and update the port statement.Example code is stored within the demo folder available from GitHub. Copy these into your project folder to test the library and connectivity.
105
106
 
106
107
  ## More Details
@@ -64,6 +64,7 @@ Example code is stored within the demo folder available on GitHub. Copy these in
64
64
 
65
65
  * The demos are created for a Raspberry Pi or other Linux computers.
66
66
  * The USB port is hard-coded as /dev/ttyACM0.
67
+ * The Loco ID is hard-coded as 3.
67
68
  * For other computers or USB ports, edit the Python file and update the port statement.Example code is stored within the demo folder available from GitHub. Copy these into your project folder to test the library and connectivity.
68
69
 
69
70
  ## More Details
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PyVLCB"
7
- version = "0.1.2"
7
+ version = "0.2.0"
8
8
  description = "A library for CBUS / VLCB communication"
9
9
  readme = {file="README.md", content-type = "text/markdown"}
10
10
  requires-python = ">=3.6"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyVLCB
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: A library for CBUS / VLCB communication
5
5
  Author-email: "Stewart Watkiss (penguintutor)" <5587863+penguintutor@users.noreply.github.com>
6
6
  License: MIT License
@@ -101,6 +101,7 @@ Example code is stored within the demo folder available on GitHub. Copy these in
101
101
 
102
102
  * The demos are created for a Raspberry Pi or other Linux computers.
103
103
  * The USB port is hard-coded as /dev/ttyACM0.
104
+ * The Loco ID is hard-coded as 3.
104
105
  * For other computers or USB ports, edit the Python file and update the port statement.Example code is stored within the demo folder available from GitHub. Copy these into your project folder to test the library and connectivity.
105
106
 
106
107
  ## More Details
@@ -3,7 +3,7 @@
3
3
 
4
4
  from .vlcbformat import VLCBFormat, VLCBOpcode
5
5
  from .canusb import CanUSB4
6
- from .utils import num_to_1hexstr, num_to_2hexstr, num_to_4hexstr, f_to_bytes
6
+ from .utils import num_to_1hexstr, num_to_2hexstr, num_to_4hexstr, f_to_bytes, dict_to_string
7
7
  from .exceptions import (
8
8
  MyLibraryError,
9
9
  DeviceConnectionError,
@@ -123,7 +123,7 @@ class VLCB:
123
123
  opcode = vlcb_entry.data[0:2]
124
124
  opcode_string = f'{opcode} - {VLCBOpcode.opcode_mnemonic(opcode)}'
125
125
  #data_string = f"{VLCBOpcode.parse_data(vlcb_entry.data)}"
126
- data_string = VLCB._dict_to_string(VLCBOpcode.parse_data(vlcb_entry.data))
126
+ data_string = dict_to_string(VLCBOpcode.parse_data(vlcb_entry.data))
127
127
  return [date_string, direction, message, str(vlcb_entry.can_id), opcode_string, data_string]
128
128
  # Todo - error handling
129
129
 
@@ -400,12 +400,42 @@ class VLCB:
400
400
  """
401
401
  return f"{self.make_header(opcode='23')}23{num_to_1hexstr(session_id)};"
402
402
 
403
+ def loco_speed_dir (self, session_id: int, speed: int, direction: int) -> str:
404
+ """Set loco speed and direction based on separate arguments
405
+
406
+ Same as loco_speeddir but this takes 2 arguments, whereas loco_speeddir needs a combined value
407
+ Maximum call this once every 32 milliseconds
408
+
409
+ Uses DSPD (47)
410
+
411
+ Args:
412
+ session_id: Session ID
413
+ speed: 0 to 127 (1 is increased to 2 to avoid emergency stop)
414
+ direction: 1 = forward, 0 = reverse
415
+
416
+ Returns:
417
+ String: A string for the request
418
+
419
+ Raises:
420
+ ValueError is speed is out of range, or invalid direction
421
+ """
422
+ if speed < 0 or speed > 127:
423
+ raise ValueError ("Invalid speed specified. Must be in range 0 to 127")
424
+ if direction <0 or direction > 1:
425
+ raise ValueError ("Direction is not valid. Use 1 for forward, 0 for reverse")
426
+ # special case - ignore emergency stop
427
+ if speed == 1:
428
+ speed = 2
429
+ speeddir = (direction * 0x80) + speed
430
+ return self.loco_speeddir (session_id, speeddir)
431
+
403
432
  # Set loco speed and direction (always done together)
404
- # Maximum once every 32 miliseconds (GUI configured based on non triggered so shouldn't be an issue)
405
- # Could add time detection if required
406
- # This uses the combined speed and direction value
407
433
  def loco_speeddir (self, session_id: int, speeddir: int) -> str:
408
- """Create a combined set speed and direction event
434
+ """Set loco speed and direction
435
+
436
+ Maximum call this once every 32 milliseconds
437
+ Needs combined speed and direction value.
438
+ If speed is set to 1 then that is considered an emergency stop
409
439
 
410
440
  Uses DSPD (47)
411
441
 
@@ -437,5 +467,28 @@ class VLCB:
437
467
  String: A string for the request
438
468
  """
439
469
  return f"{self.make_header(opcode='60')}60{num_to_1hexstr(session_id)}{num_to_1hexstr(byte1)}{num_to_1hexstr(byte2)};"
440
-
441
470
 
471
+ def loco_set_function (self, session_id: int, function_num, function_list) -> str:
472
+ """Create a set function request using the function list
473
+ Sends the entire group of functions where the function_num resides
474
+ This is an alternative to loco_set_dfun as this calculates the bytes
475
+ this method can only be used for functions 0 to 27
476
+
477
+ Uses DFUN (60)
478
+
479
+ Args:
480
+ session_id: Session ID
481
+ byte1: Function number
482
+ byte2: List of current function statuses
483
+
484
+ Returns:
485
+ String: A string for the request
486
+
487
+ Raises:
488
+ ValueError: Typically raised from f_to_bytes
489
+ """
490
+ byte1_2 = f_to_bytes(function_num, function_list)
491
+ return f"{self.make_header(opcode='60')}60{num_to_1hexstr(session_id)}{byte1_2[0]}{byte1_2[1]};"
492
+
493
+
494
+
@@ -22,7 +22,8 @@ class CanUSB4 ():
22
22
  def __init__ (self,
23
23
  port: str,
24
24
  baud: Optional[int] = 115200,
25
- timeout: Optional[float] = 0.01) -> None:
25
+ timeout: Optional[float] = 0.01,
26
+ exclusive: Optional[bool] = True) -> None:
26
27
  """Inits CanUSB4 with a USB port
27
28
 
28
29
  Args:
@@ -41,6 +42,10 @@ class CanUSB4 ():
41
42
  self.timeout = timeout
42
43
  self.max_retry = 30 # How many times to attempt on get_data must be at least as long as frame
43
44
  # Timeout for a request could be max_rety x timeout
45
+ self.exclusive = exclusive # Exclusive determines if check for exclusive use of the USB port
46
+ # If this is set to false then if another application is already using the port then the application
47
+ # will run, but appear to hang if there is no response because another thread has already
48
+ # taken the incoming data
44
49
 
45
50
  if not port:
46
51
  raise InvalidConfigurationError("Port name cannot be empty")
@@ -53,7 +58,11 @@ class CanUSB4 ():
53
58
 
54
59
 
55
60
  # Optional arguments override existing
56
- def connect(self, port=None, baud=None, timeout=None):
61
+ def connect(self,
62
+ port: Optional[str] = None,
63
+ baud: Optional[int] = None,
64
+ timeout: Optional[float] = None,
65
+ exclusive: Optional[bool] = None) -> None:
57
66
  """Inits CanUSB4 with a USB port
58
67
 
59
68
  Args:
@@ -74,8 +83,15 @@ class CanUSB4 ():
74
83
  self.baud = baud
75
84
  if timeout != None:
76
85
  self.timeout = timeout
86
+ if exclusive != None:
87
+ self.exclusive = exclusive
77
88
  try:
78
- self.ser = serial.Serial(self.port, self.baud, timeout=self.timeout)
89
+ self.ser = serial.Serial(
90
+ self.port,
91
+ self.baud,
92
+ timeout=self.timeout,
93
+ exclusive = exclusive
94
+ )
79
95
  except serial.SerialException as e:
80
96
  raise DeviceConnectionError(f"Could not open port {self.port}") from e
81
97
  if self.ser:
@@ -57,4 +57,12 @@ class InvalidLocoError(MyLibraryError):
57
57
  or short code specified but code needs long code
58
58
  or if the packet does not contain a loco_id (eg. certain Err codes)
59
59
  """
60
+ pass
61
+
62
+ class InvalidFunctionError(MyLibraryError):
63
+ """
64
+ Raised for an invalid function requests
65
+ For example asking for function information
66
+ from a response which doesn't include the function information.
67
+ """
60
68
  pass
@@ -34,7 +34,7 @@ class TestCanUSB4(unittest.TestCase):
34
34
  def test_init_valid(self):
35
35
  """Test that initialization opens the serial port with correct settings."""
36
36
  # Check if serial.Serial was called with correct args
37
- self.mock_serial_class.assert_called_with(self.port, 115200, timeout=0.01)
37
+ self.mock_serial_class.assert_called_with(self.port, 115200, timeout=0.01, exclusive=None)
38
38
 
39
39
  def test_init_empty_port(self):
40
40
  """Test that empty port raises InvalidConfigurationError."""
@@ -88,10 +88,10 @@ class TestVLCB(unittest.TestCase):
88
88
  #f_to_bytes (f_num: int, function_status: List[int]) -> Tuple[bytes, bytes]
89
89
  def test_f_to_bytes(self):
90
90
  functions = [1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1]
91
- self.assertEqual(f_to_bytes (1, functions), (1, 25))
92
- self.assertEqual(f_to_bytes (2, functions), (1, 25))
93
- self.assertEqual(f_to_bytes (7, functions), (2, 6))
94
- self.assertEqual(f_to_bytes (24, functions), (5, 0))
91
+ self.assertEqual(f_to_bytes (1, functions), ("01", "19"))
92
+ self.assertEqual(f_to_bytes (2, functions), ("01", "19"))
93
+ self.assertEqual(f_to_bytes (7, functions), ("02", "06"))
94
+ self.assertEqual(f_to_bytes (24, functions), ("05", "00"))
95
95
 
96
96
 
97
97
  if __name__ == "__main__":
@@ -40,7 +40,7 @@ def num_to_4hexstr (num: int) -> str:
40
40
 
41
41
 
42
42
  # dict to string without {} or ""
43
- def _dict_to_string (dictionary: dict) -> str:
43
+ def dict_to_string (dictionary: dict) -> str:
44
44
  """ Convert a dict to a string without {} or quotes """
45
45
  data_string = ""
46
46
  for key, value in dictionary.items():
@@ -49,8 +49,8 @@ def _dict_to_string (dictionary: dict) -> str:
49
49
  data_string += f"{key} = {value}"
50
50
  return data_string
51
51
 
52
- def f_to_bytes (f_num: int, function_status: List[int]) -> Tuple[bytes, bytes]:
53
- """ Convert a Fnumber (Loco function ID) to bytes
52
+ def f_to_bytes (f_num: int, function_status: List[int]) -> Tuple[str, str]:
53
+ """ Convert a Fnumber (Loco function ID) to bytes as string representation
54
54
 
55
55
  Can be used to create correct format for loco_set_dfun
56
56
  Limited to range 0 to 28 - which is max for DFUN
@@ -61,7 +61,7 @@ def f_to_bytes (f_num: int, function_status: List[int]) -> Tuple[bytes, bytes]:
61
61
  function_status: List with value of all functions (must be updated before calling)
62
62
 
63
63
  Returns:
64
- Tuple of two bytes
64
+ Tuple of two x 2-characer strings representing the bytes
65
65
 
66
66
  Raises: ValueError
67
67
 
@@ -117,7 +117,11 @@ def f_to_bytes (f_num: int, function_status: List[int]) -> Tuple[bytes, bytes]:
117
117
  0b1000000 * function_list[27] +
118
118
  0b10000000 * function_list[28]
119
119
  )
120
- return (byte1, byte2)
120
+ # convert to strings before returning
121
+ # and with 0xFF guarentees it doesn't overflow (although not really neccessary for this method)
122
+ str1 = f"{ (byte1 & 0xFF) :02x}"
123
+ str2 = f"{ (byte2 & 0xFF) :02x}"
124
+ return (str1, str2)
121
125
 
122
126
 
123
127
  # Where 2 bytes convert to addr id
@@ -148,3 +152,29 @@ def bytes_to_hexstr (byte1: bytes, byte2: bytes) -> str:
148
152
  """
149
153
  return f"{hex(byte1).upper()[2:]:0>2}{hex(byte2).upper()[2:]:0>2}"
150
154
 
155
+
156
+ def bytes_to_functions (fn1: bytes, fn2: bytes, fn3: bytes) -> List[int]:
157
+ """ Sets the value of the functions from a PLOC message
158
+ Only returns values for F0 to F12 (others not included in PLOC)
159
+ Provides as a list for inclusion in menus etc.
160
+
161
+ Args:
162
+ fn1: Function byte F0 to F4 - bit 5 = dir lighting (F0), bit 6 = direction, bit 7 = res, bit 8 = 0
163
+ fn2: Function byte F5 to F8 - bit 5 upwards reserved
164
+ fn3: Function byte F9 to F12
165
+
166
+ Returns:
167
+ List of function values as 0 or 1 for each function as off and on
168
+
169
+ """
170
+ data_in = [fn1, fn2, fn3]
171
+ mask = [0b0001, 0b0010, 0b0100, 0b1000]
172
+ function_status = [0] * 29
173
+ # Handle 0 separately as it's in the upper nibble
174
+ function_status[0] = data_in[0] & 0b10000
175
+ # Create a list of 12 entries
176
+ for i in range (0, 3):
177
+ for j in range (0, 4):
178
+ function_status[(i*4)+j+1] = 1 if (data_in[i] & mask[j]) > 0 else 0
179
+
180
+ return function_status
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  import warnings
3
- from .utils import bytes_to_addr
3
+ from .utils import bytes_to_addr, bytes_to_functions
4
4
  from typing import List, Optional, Union, Dict, Any
5
5
 
6
6
  # Set up a null handler so nothing prints by default unless the user enables it
@@ -108,6 +108,29 @@ class VLCBFormat :
108
108
  else:
109
109
  raise InvalidLocoError(f"Opcode {self.opcode()} does not contain a loco_id")
110
110
 
111
+ def get_function_list (self) -> List[int]:
112
+ """Where packet contains Fn1, Fn2, Fn3 (eg. PLOC)
113
+ returns
114
+
115
+ Only valid with certain VLCBFormat packets associated with Locos.
116
+ If packet is does not contain the 3 byte values (which
117
+ may be formatted differently) then raises a InvalidFunctionError
118
+
119
+ Returns:
120
+ List of function values as 0 or 1 for each function as off and on
121
+
122
+ Raises:
123
+ InvalidFunctionError: If Function Bytes are not in the packet
124
+ """
125
+ if self.opcode() == "PLOC":
126
+ # Get data
127
+ data_dict = VLCBOpcode.parse_data(self.data)
128
+ return bytes_to_functions (data_dict['Fn1'], data_dict['Fn2'], data_dict['Fn3'])
129
+ else:
130
+ raise InvalidLocoError(f"Opcode {self.opcode()} does not contain a loco_id")
131
+
132
+
133
+
111
134
 
112
135
  def __str__ (self):
113
136
  return f'{self.priority} : {self.can_id} : {self.opcode()} ({self.data[0:2]}) : {self.data} / {self.format_data()}'
@@ -174,30 +197,32 @@ class VLCBOpcode:
174
197
  '50': {'opc': 'RQNN', 'title': 'Request node number', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a node that is in setup/configuration mode and requests assignment of a node number (NN). The node allocating node numbers responds with (SNN) which contains the newly assigned node number. <NN hi> and <NN lo> are the existing node number, if the node has one. If it does not yet have a node number, these bytes should be set to zero.'},
175
198
  '51': {'opc': 'NNREL', 'title': 'Node number release', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by node when taken out of service. e.g. when reverting to SLiM mode.'},
176
199
  '52': {'opc': 'NNACK', 'title': 'Node number acknowledge', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a node to verify its presence and confirm its node id. This message is sent to acknowledge an SNN.'},
177
- '53': {'opc': 'NNLRN', 'title': 'Set node into learn mode', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a configuration tool to put a specific node into learn mode.'},
200
+ '53': {'opc': 'NNLRN', 'title': 'Set node into learn mode', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a configuration tool to put a specific node into learn mode. Deprecated - replaced by MODE'},
178
201
  '54': {'opc': 'NNULN', 'title': 'Release node from learn mode', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a configuration tool to take node out of learn mode and revert to normal operation.'},
179
202
  '55': {'opc': 'NNCLR', 'title': 'Clear all events from a node', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a configuration tool to clear all events from a specific node. Must be in learn mode first to safeguard against accidental erasure of all events.'},
180
203
  '56': {'opc': 'NNEVN', 'title': 'Read number of events available in a node', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a configuration tool to read the number of available event slots in a node.Response is EVLNF (0x70)'},
181
204
  '57': {'opc': 'NERD', 'title': 'Read back all stored events in a node', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a configuration tool to read all the stored events in a node. Response is 0xF2.'},
182
205
  '58': {'opc': 'RQEVN', 'title': 'Request to read number of stored events', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a configuration tool to read the number of stored events in a node. Response is 0x74( NUMEV).'},
183
- '59': {'opc': 'WRACK', 'title': 'Write acknowledge', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a node to indicate the completion of a write to memory operation. All nodes must issue WRACK when a write operation to node variables, events or event variables has completed. This allows for teaching nodes where the processing time may be slow.'},
206
+ '59': {'opc': 'WRACK', 'title': 'Write acknowledge', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by a node to indicate the completion of a write to memory operation. All nodes must issue WRACK when a write operation to node variables, events or event variables has completed. This allows for teaching nodes where the processing time may be slow. Deprecated replaced by GRSP'},
184
207
  '5A': {'opc': 'RQDAT', 'title': 'Request node data event', 'format': 'NN', 'minpri': 3, 'comment': 'Sent by one node to read the data event from another node.(eg: RFID data). Response is 0xF7 (ARDAT).'},
185
208
  # DN = Device number
186
209
  '5B': {'opc': 'RQDDS', 'title': 'Request device data - short mode', 'format': 'DNHigh_DNLow', 'minpri': 3, 'comment': 'To request a data set from a device using the short event method. where DN is the device number. Response is 0xFB (DDRS)'},
187
- '5C': {'opc': 'BOOTM', 'title': 'Put node into bootload mode', 'format': 'NN', 'minpri': 3, 'comment': 'For SliM nodes with no NN then the NN of the command must be zero. For SLiM nodes with an NN, and all FLiM nodes the command must contain the NN of the target node. Sent by a configuration tool to prepare for loading a new program.'},
188
- '5D': {'opc': 'ENUM', 'title': 'Force a self enumeration cyble for use with CAN', 'format': 'NN', 'minpri': 3, 'comment': 'For nodes in FLiM using CAN as transport. This OPC will force a self-enumeration cycle for the specified node. A new CAN_ID will be allocated if needed. Following the ENUM sequence, the node should issue a NNACK to confirm completion and verify the new CAN_ID. If no CAN_ID values are available, an error message 7 will be issued instead.'},
210
+ '5C': {'opc': 'BOOTM', 'title': 'Put node into bootload mode', 'format': 'NN', 'minpri': 3, 'comment': 'For SliM nodes with no NN then the NN of the command must be zero. For SLiM nodes with an NN, and all FLiM nodes the command must contain the NN of the target node. Sent by a configuration tool to prepare for loading a new program. Deprecated replaced by MODE'},
211
+ '5D': {'opc': 'ENUM', 'title': 'Force a self enumeration cyble for use with CAN', 'format': 'NN', 'minpri': 3, 'comment': 'For nodes in FLiM using CAN as transport. This OPC will force a self-enumeration cycle for the specified node. A new CAN_ID will be allocated if needed. Following the ENUM sequence, the node should issue a NNACK to confirm completion and verify the new CAN_ID. If no CAN_ID values are available, an error message 7 will be issued instead. Deprecated replaced with automatic self enumeration.'},
189
212
  '5F': {'opc': 'EXTC1', 'title': 'Extended op-code with 1 additional byte', 'format': 'ExtOpc,Byte1', 'minpri': 3, 'comment': 'Used if the basic set of 32 OPCs is not enough. Allows an additional 256 OPCs'},
190
213
  # 3rd data section
191
214
  '60': {'opc': 'DFUN', 'title': 'Set Engine functions', 'format': 'Session,Fn1,Fn2', 'minpri': 2, 'comment': '<Dat2> (Fn1) is the function range. 1 is F0(FL) to F4; 2 is F5 to F8; 3 is F9 to F12; 4 is F13 to F20; 5 is F21 to F28; <Dat3> (Fn2) is the NMRA DCC format function byte for that range in corresponding bits. Sent by a CAB or equivalent to request an engine Fn state change.'},
192
215
  '61': {'opc': 'GLOC', 'title': 'Get engine session', 'format': 'AddrHigh_AddrLow,Flags', 'minpri': 2, 'comment': '<Dat1> and <Dat2> are [AddrH] and [AddrL] of the decoder, respectively.; 7 bit addresses have (AddrH=0).; 14 bit addresses have bits 6,7 of AddrH set to 1.; <Flags> contains flag bits as follows:Bit 0: Set for "Steal" mode; Bit 1: Set for "Share" mode; Both bits set to 0 is exactly equivalent to an RLOC request; Both bits set to 1 is invalid, because the 2 modes are mutually exclusive; The command station responds with (PLOC) if the request is successful. Otherwise responds with (ERR): engine in use. (ERR:) stack full or (ERR) no session. The latter indicates that there is no current session to steal/share depending on the flag bits set in the request. GLOC with all flag bits set to zero is exactly equivalent to RLOC, but command stations must continue to support RLOC for backwards compatibility.'},
193
216
  '63': {'opc': 'ERR', 'title': 'Command station error report', 'format': 'Byte1,Byte2,ErrCode', 'minpri': 2, 'comment': 'Sent in response to an error situation by a command station.'},
194
- '6F': {'opc': 'CMDERR', 'title': 'Error messages from nodes during configuration', 'format': 'NN,Error', 'minpri': 3, 'comment': 'Sent by node if there is an error when a configuration command is sent.'},
217
+ '6F': {'opc': 'CMDERR', 'title': 'Error messages from nodes during configuration', 'format': 'NN,Error', 'minpri': 3, 'comment': 'Sent by node if there is an error when a configuration command is sent. Deprecated replaced by GRSP.'},
195
218
  '70': {'opc': 'EVNLF', 'title': 'Event space left reply from node', 'format': 'NN,EVSPC', 'minpri': 3, 'comment': 'EVSPC is a one byte value giving the number of available events left in that node.'},
196
- '71': {'opc': 'NVRD', 'title': 'Request read of a node variable', 'format': 'NN,NVIndex', 'minpri': 3, 'comment': 'NV# is the index for the node variable value requested. Response is NVANS.'},
219
+ '71': {'opc': 'NVRD', 'title': 'Request read of a node variable', 'format': 'NN,NVIndex', 'minpri': 3, 'comment': 'NV# is the index for the node variable value requested. Response is NVANS. VLCB also returns GRSP and support for NV#0.'},
197
220
  '72': {'opc': 'NENRD', 'title': 'Request read of stored events by event index', 'format': 'NN,EnIndex', 'minpri': 3, 'comment': 'EN# is the index for the stored event requested. Response is 0xF2 (ENRSP)'},
198
- '73': {'opc': 'RQNPN', 'title': 'Request read of a node parameter by index', 'format': 'NN,ParaIndex', 'minpri': 3, 'comment': 'Para# is the index for the parameter requested. Index 0 returns the number of available parameters, Response is 0x9B (PARAN).'},
221
+ '73': {'opc': 'RQNPN', 'title': 'Request read of a node parameter by index', 'format': 'NN,ParaIndex', 'minpri': 3, 'comment': 'Para# is the index for the parameter requested. Index 0 returns the number of available parameters, Response is 0x9B (PARAN). VLCB Para #0 returns a PARAN for each parameter'},
199
222
  '74': {'opc': 'NUMEV', 'title': 'Number of events stored in node', 'format': 'NN,NumEvents', 'minpri': 3, 'comment': 'Response to request 0x58 (RQEVN)'},
200
- '75': {'opc': 'CANID', 'title': 'Set a CAN_ID in existing FLiM node', 'format': 'NN,CAN_ID', 'minpri': 0, 'comment': 'Used to force a specified CAN_ID into a node. Value range is from 1 to 0x63 (99 decimal) This OPC must be used with care as duplicate CAN_IDs are not allowed. Values outside the permitted range will produce an error 7 message and the CAN_ID will not change.'},
223
+ '75': {'opc': 'CANID', 'title': 'Set a CAN_ID in existing FLiM node', 'format': 'NN,CAN_ID', 'minpri': 0, 'comment': 'Used to force a specified CAN_ID into a node. Value range is from 1 to 0x63 (99 decimal) This OPC must be used with care as duplicate CAN_IDs are not allowed. Values outside the permitted range will produce an error 7 message and the CAN_ID will not change. Deprecated replaced with self-enumaration. VLCB includes GRSP responses.'},
224
+ '76': {'opc': 'MODE', 'title': 'Request a change to a modules operating mode', 'format': 'NN,ModeCmd', 'minpri': 0, 'comment': 'Request to change the operational mode of the module. Mode cmds 0 = transition to setup mode, 1 = transition to normal mode, 16 = turn on FCU compat, 17 = turn off FCU compat. If supported then module returns GRSP. VLCB new features.'},
225
+ '78': {'opc': 'RQSD', 'title': 'Request service discover', 'format': 'NN,ServiceIndex', 'minpri': 0, 'comment': 'Request service data from a module if ServiceIndex is 0 then SD message sent, followed by ESD response for each services supported. VLCB new feature.'},
201
226
  '7F': {'opc': 'EXTC2', 'title': 'Extended op-code with 2 additional bytes', 'format': 'ExtOpc,Byte1,Byte2', 'minpri': 0, 'comment': 'Used if the basic set of 32 OPCs is not enough. Allows an additional 256 OPCs'},
202
227
  # 4 data byte packets
203
228
  '80': {'opc': 'RDCC3', 'title': 'Request 3-byte DCC Packet', 'format': 'Rep,Byte1,Byte2,Byte3', 'minpri': 3, 'comment': '<Dat1(REP)> is number of repetitions in sending the packet. <Dat2>..<Dat4> 3 bytes of the DCC packet. Allows a CAB or equivalent to request a 3 byte DCC packet to be sent to the track. The packet is sent <REP> times and is not refreshed on a regular basis. Note: a 3 byte DCC packet is the minimum allowed.'},
@@ -205,14 +230,16 @@ class VLCBOpcode:
205
230
  '83': {'opc': 'WCVB', 'title': 'Write CV (bit) in OPS mode', 'format': 'Session,CVHigh_CVLow,CVVal', 'minpri': 2, 'comment': '<Dat1> is the session number of the loco to be written to; <Dat2> is the MSB # of the CV to be written (supports CVs 1 - 65536); <Dat3> is the LSB # of the CV to be written; <Dat4> is the value to be written; The format for Dat4 is that specified in RP 9.2.1 for OTM bit manipulation in a DCC packet.; This is ?111CDBBB? where C is here is always 1 as only ?writes? are possible OTM. (unless some loco ACK scheme like RailCom is used). D is the bit value, either 0 or 1 and BBB is the bit position in the CV byte. 000 to 111 for bits 0 to 7.; Sent to the command station to write a DCC CV in OPS mode to specific loco.(on the main)'},
206
231
  '84': {'opc': 'QCVS', 'title': 'Read CV', 'format': 'Session,CVHigh_CVLow,Mode', 'minpri': 2, 'comment': 'This command is used exclusively with service mode.; Sent by the cab to the command station in order to read a CV value. The command station shall respond with a PCVS message containing the value read, or SSTAT if the CV cannot be read.'},
207
232
  '85': {'opc': 'PCVS', 'title': 'Report CV', 'format': 'Session,CVHigh_CVLow,CVVal', 'minpri': 2, 'comment': '<Dat1> is the session number of the cab; <Dat2> is the MSB # of the CV read (supports CVs 1 - 65536); <Dat3> is the LSB # of the CV read; <Dat4> is the read value; This command is used exclusively with service mode.; Sent by the command station to report a read CV.'},
233
+ '87': {'opc': 'RDGN', 'title': 'Request dianostic data', 'format': 'NN,ServiceIndex,DiagCode', 'minpri': 0, 'comment': 'Request diagnostic data from a module. If DiagCode is 0 then all data returned. If ServiceIndex 0 then send DGN message for each service, otherwise send DGN for service specified'},
234
+ '8E': {'opc': 'NVSETRD', 'title': 'Set an NV value with read back', 'format': 'NN,NNIndex,NVVal', 'minpri': 0, 'comment': 'Sets an NV value and responds with the new value, response may not be the value requested. VLCB new feature.'},
208
235
  '90': {'opc': 'ACON', 'title': 'Accessory ON', 'format': 'NN,EnHigh_EnLow', 'minpri': 3, 'comment': '<Dat1> is the high byte of the node number; <Dat2> is the low byte of the node number; <Dat3> is the high byte of the event number; <Dat4> is the low byte of the event number; Indicates an ?ON? event using the full event number of 4 bytes. (long event)'},
209
236
  '91': {'opc': 'ACOF', 'title': 'Accessory OFF', 'format': 'NN,EnHigh_EnLow', 'minpri': 3, 'comment': '<Dat1> is the high byte of the node number; <Dat2> is the low byte of the node number; <Dat3> is the high byte of the event number; <Dat4> is the low byte of the event number; Indicates an ?OFF? event using the full event number of 4 bytes. (long event)'},
210
237
  '92': {'opc': 'AREQ', 'title': 'Accessory Request Event', 'format': 'NN,EnHigh_EnLow', 'minpri': 3, 'comment': '<Dat1> is the high byte of the node number (MS WORD of the full event #); <Dat2> is the low byte of the node number (MS WORD of the full event #); <Dat3> is the high byte of the event number; <Dat4> is the low byte of the event number; Indicates a ?request? event using the full event number of 4 bytes. (long event); A request event is used to elicit a status response from a producer when it is required to know the state of the producer without producing an ON or OFF event and to trigger an event from a combi node'},
211
238
  '93': {'opc': 'ARON', 'title': 'Accessory Response Event', 'format': 'NN,EnHigh_EnLow', 'minpri': 3, 'comment': 'Indicates an ?ON? response event. A response event is a reply to a status request (AREQ) without producing an ON or OFF event.'},
212
239
  '94': {'opc': 'AROF', 'title': 'Accessory Response Event', 'format': 'NN,EnHigh_EnLow', 'minpri': 3, 'comment': '<Dat1> is the high byte of the node number; <Dat2> is the low byte of the node number; <Dat3> is the high byte of the event number; <Dat4> is the low byte of the event number; Indicates an ‘OFF’ response event. A response event is a reply to a status request; (AREQ) without producing an ON or OFF event'},
213
- '95': {'opc': 'EVULN', 'title': 'Unlearn an event in learn mode', 'format': 'NN,EnHigh_EnLow', 'minpri': 3, 'comment': 'Sent by a configuration tool to remove an event from a node.'},
240
+ '95': {'opc': 'EVULN', 'title': 'Unlearn an event in learn mode', 'format': 'NN,EnHigh_EnLow', 'minpri': 3, 'comment': 'Sent by a configuration tool to remove an event from a node. VLCB also return GRSP.'},
214
241
  # NVIndex is NV Index number
215
- '96': {'opc': 'NVSET', 'title': 'Set a node variable', 'format': 'NN,NVIndex,NVVal', 'minpri': 3, 'comment': 'Sent by a configuration tool to set a node variable. NV# is the NV index number.'},
242
+ '96': {'opc': 'NVSET', 'title': 'Set a node variable', 'format': 'NN,NVIndex,NVVal', 'minpri': 3, 'comment': 'Sent by a configuration tool to set a node variable. NV# is the NV index number. Deprecated replaced by NVSETRD. VLCB also return GRSP.'},
216
243
  '97': {'opc': 'NVANS', 'title': 'Response to a request for a node variable value', 'format': 'NN,NVIndex,NVVal', 'minpri': 3, 'comment': 'Sent by node in response to request. (NVRD)'},
217
244
  # Short events
218
245
  # DNHigh, DNLow = Lower two bytes define device number - considered same as a device address - full 4byte event is still sent
@@ -237,6 +264,9 @@ class VLCBOpcode:
237
264
  # Mode - service write mode
238
265
  #CVVal - CV value
239
266
  'A2': {'opc': 'WCVS', 'title': 'Write CV in Service Mode', 'format': 'Session,CVHigh_CVLow,Mode,CVVal', 'minpri': 0, 'comment': '<Dat1> is the session number of the cab; <Dat2> is the MSB # of the CV to be written (supports CVs 1 - 65536); <Dat3> is the LSB # of the CV to be written; <Dat4> is the service write mode; <Dat5> is the CV value to be written; Sent to the command station to write a DCC CV in service mode.'},
267
+ 'AB': {'opc': 'HEARTB', 'title': 'Heartbeat message from module', 'format': 'NN,Sequence,Status,StatusBits', 'minpri': 0, 'comment': 'Hearbeat message from module indicating alive. Sent every 5 seconds by module. Sequence count from 0, incrementing and wrap around to 0., Statis is binary representation of diagnostic status 0x00 is normal operation. StatusBits is reserved set to 0x00. VLCB new feature.'},
268
+ 'AC': {'opc': 'SD', 'title': 'Service discovery response', 'format': 'NN,ServiceIndex,ServiceType,Version', 'minpri': 0, 'comment': 'Version of service supported response to RQSD with ServiceIndex = 0. First SD response is number of following SD responses. Also see ESD. VLCB new feature.'},
269
+ 'AF': {'opc': 'GRSP', 'title': 'Generic response', 'format': 'NN,Opcode,ServiceType,Result', 'minpri': 0, 'comment': 'Generic response for a config change request. Result byte indicates ok for success or error code. CMDERR codes are supported. VLCB new feature.'},
240
270
  'B0': {'opc': 'ACON1', 'title': 'Accessory ON', 'format': 'NN,EnHigh_EnLow,Byte1', 'minpri': 3, 'comment': '<Dat1> is the high byte of the node number; <Dat2> is the low byte of the node number; <Dat3> is the high byte of the event number; <Dat4> is the low byte of the event number; <Dat5> is an additional data byte; Indicates an ‘ON’ event using the full event number of; 4 bytes with one additional data byte.'},
241
271
  'B1': {'opc': 'ACOF1', 'title': 'Accessory OFF', 'format': 'NN,EnHigh_EnLow,Byte1', 'minpri': 3, 'comment': '<Dat1> is the high byte of the node number; <Dat2> is the low byte of the node number; <Dat3> is the high byte of the event number; <Dat4> is the low byte of the event number; <Dat5> is an additional data byte; Indicates an ‘OFF’ event using the full event number of 4 bytes with one additional data byte.'},
242
272
  'B2': {'opc': 'REQEV', 'title': 'Read event variable in learn mode', 'format': 'NN,EnHigh_EnLow,EvIndex', 'minpri': 3, 'comment': 'Allows a configuration tool to read stored event variables from a node. EV# is the EV index. Reply is (EVANS)'},
@@ -250,14 +280,16 @@ class VLCBOpcode:
250
280
  'B9': {'opc': 'ASOF1', 'title': 'Accessory Short OFF', 'format': 'NN,DNHigh_DNLow,Byte1', 'minpri': 3, 'comment': 'Indicates an ‘OFF’ event using the short event number of 2 LS bytes with one added data byte.'},
251
281
  'BD': {'opc': 'ARSON1', 'title': 'Accessory Short Response Event with one data byte', 'format': 'NN,DNHigh_DNLow,Byte1', 'minpri': 3, 'comment': 'Indicates an ‘ON’ response event with one added data byte. A response event is a reply to a status request (ASRQ) without producing an ON or OFF event.'},
252
282
  'BE': {'opc': 'ARSOF1', 'title': 'Accessory short response event with one data byte', 'format': 'NN,DNHigh_DNLow,Byte1', 'minpri': 3, 'comment': 'Indicates an ‘OFF’ response event with one added data byte. A response event is a reply to a status request (ASRQ) without producing an ON or OFF event.'},
253
- 'BF': {'opc': 'EXTC4', 'title': 'Extended op-code with 4 data bytes', 'format': 'ExtOpc,Byte1,Byte2,Byte3,Byte4', 'minpri': 3, 'comment': 'Used if the basic set of 32 OPCs is not enough. Allows an additional 256 OPCs'},
283
+ 'BF': {'opc': 'EXTC4', 'title': 'Extended op-code with 4 data bytes', 'format': 'ExtOpc,Byte1,Byte2,Byte3,Byte4', 'minpri': 3, 'comment': 'Used if the basic set of 32 OPCs is not enough. Allows an additional 256 OPCs.'},
254
284
  # 6 data byte packets
255
285
  'C0': {'opc': 'RDCC5', 'title': 'Requst 5-byte DCC packet', 'format': 'Rep,Byte1,Byte2,Byte3,Byte4,Byte5', 'minpri': 2, 'comment': '<Dat1(REP)> is # of repetitions in sending the packet.; <Dat2>..<Dat6> 5 bytes of the DCC packet.; Allows a CAB or equivalent to request a 5 byte DCC packet to be sent to the track. The packet is sent <REP> times and is not refreshed on a regular basis.'},
256
286
  'C1': {'opc': 'WCVOA', 'title': 'Write CV (byte) in OPS mode by address', 'format': 'AddrHigh_AddrLow,CVHigh_CVLow,Mode,CVVal', 'minpri': 2, 'comment': '<Dat1> and <Dat2> are [AddrH] and [AddrL] of the decoder, respectively.; 7 bit addresses have (AddrH=0).; 14 bit addresses have bits 7,8 of AddrH set to 1.; <Dat3> is the MSB # of the CV to be written (supports CVs 1 - 65536); <Dat4> is the LSB # of the CV to be written; <Dat5> is the programming mode to be used; <Dat6> is the CV byte value to be written; Sent to the command station to write a DCC CV byte in OPS mode to specific loco (on the main). Used by computer based ops mode programmer that does not have a valid throttle handle.'},
287
+ 'C2': {'opc': 'CABDAT', 'title': 'Send data to DCC CAB which is controlling loco', 'format': 'AddrHigh_AddrLow,DataCode,Byte1,Byte2,Byte3', 'minpri': 1, 'comment': 'Send data to DCC CAB controlling particular loco. CABSIG data1 for aspect1, data2 for aspect2, data3 for speed. Defined in RFC0005.'},
288
+ 'C7': {'opc': 'DGN', 'title': 'Dianostic data resonse', 'format': 'NN,ServiceIndex,DiagCode,DiagVal', 'minpri': 0, 'comment': 'Diagnostic data value from a module sent in response to RDGN. VLCB new features'},
257
289
  'CF': {'opc': 'FCLK', 'title': 'Fast Clock', 'format': 'DateTime', 'minpri': 3, 'comment': 'This addendum defines a time encoding'},
258
290
  'D0': {'opc': 'ACON2', 'title': 'Accessory ON', 'format': 'NN,EnHigh_EnLow,Byte1,Byte2', 'minpri': 3, 'comment': 'Indicates an ‘ON’ event using the full event number of 4 bytes with two additional data bytes.'},
259
291
  'D1': {'opc': 'ACOF2', 'title': 'Accessory OFF', 'format': 'NN,EnHigh_EnLow,Byte1,Byte2', 'minpri': 3, 'comment': 'ndicates an ‘OFF’ event using the full event number of 4 bytes with two additional data bytes.'},
260
- 'D2': {'opc': 'EVLRN', 'title': 'Teach an event in learn mode', 'format': 'NN,EnHigh_EnLow,EvIndex,EvVal', 'minpri': 3, 'comment': 'A node response to a request from a configuration tool for the EVs associated with an event (REQEV). For multiple EVs, there will be one response per request.'},
292
+ 'D2': {'opc': 'EVLRN', 'title': 'Teach an event in learn mode', 'format': 'NN,EnHigh_EnLow,EvIndex,EvVal', 'minpri': 3, 'comment': 'A node response to a request from a configuration tool for the EVs associated with an event (REQEV). For multiple EVs, there will be one response per request. VLCB also return GRSP.'},
261
293
  'D3': {'opc': 'EVANS', 'title': 'Response to a request for an EV value in a node in learn mode', 'format': 'NN,EnHigh_EnLow,EvIndex,EvVal', 'minpri': 3, 'comment': 'A node response to a request from a configuration tool for the EVs associated with an event (REQEV). For multiple EVs, there will be one response per request.'},
262
294
  'D4': {'opc': 'ARON2', 'title': 'Accessory Response Event', 'format': 'NN,EnHigh_EnLow,Byte1,Byte2', 'minpri': 3, 'comment': 'Indicates an ‘ON’ response event with two added data bytes. A response event is a reply to a status request (AREQ) without producing an ON or OFF event.'},
263
295
  'D5': {'opc': 'AROF2', 'title': 'Accessory Response Event', 'format': 'NN,EnHigh_EnLow,Byte1,Byte2', 'minpri': 3, 'comment': 'Indicates an ‘OFF’ response event with two added data bytes. A response event is a reply to a status request (AREQ) without producing an ON or OFF event.'},
@@ -270,19 +302,22 @@ class VLCBOpcode:
270
302
  'E1': {'opc': 'PLOC', 'title': 'Engine Report', 'format': 'Session,AddrHigh_AddrLow,SpeedDir,Fn1,Fn2,Fn3', 'minpri': 2, 'comment': '<Dat4> is the Speed/Direction value. Bit 7 is the direction bit and bits 0-6 are the speed value.; <Dat5> is the function byte F0 to F4; <Dat6> is the function byte F5 to F8; <Dat7> is the function byte F9 to F12; A report of an engine entry sent by the command station. Sent in response to QLOC or as an acknowledgement of acquiring an engine requested by a cab (RLOC or GLOC).'},
271
303
  'E2': {'opc': 'NAME', 'title': 'Response to request for node name string', 'format': 'Char1_7', 'minpri': 3, 'comment': 'A node response while in ‘setup’ mode for its name string. Reply to (RQMN). The string for the module type is returned in char1 to char7, space filled to 7 bytes. The Module Name prefix , currently either CAN or ETH, depends on the Interface Protocol parameter, it is not included in the response, see section 12.2 for the definition of the parameters.'},
272
304
  'E3': {'opc': 'STAT', 'title': 'Command station status report', 'format': 'NN,CSNum,Flags,MajRev,MinRev,Build', 'minpri': 2, 'comment': '<NN hi> <NN lo> Gives node id of command station, so further info can be got from parameters or interrogating NVs; <CS num> For future expansion - set to zero at present; <flags> Flags as defined below; <Major rev> Major revision number; <Minor rev> Minor revision letter; <Build no.> Build number, always 0 for a released version.; <flags> is status defined by the bits below.; bits:; 0 - Hardware Error (self test); 1 - Track Error; 2 - Track On/ Off; 3 - Bus On/ Halted; 4 - EM. Stop all performed; 5 - Reset done; 6 - Service mode (programming) On/ Off; 7 – reserved; Sent by the command station in response to RSTAT.'},
305
+ 'E7': {'opc': 'ESD', 'title': 'Extended service discovery response', 'format': 'NN,ServiceIndex,ServiceType,Byte1,Byte2,Byte3', 'minpri':0, 'comment': 'Detailed information about a service supported by a module. Sent in response to RQSD where ServiceIndex is not 0. VLCB new feature'},
306
+ 'E9': {'opc': 'DTXC', 'title': 'Streaming protocol', 'format': 'StreamID,Sequence,Byte1,Byte2,Byte3,Byte4,Byte5', 'minpri': 0, 'comment': 'Used to transport relatively large block of data. StreamID is unique layout wide (> 20). If Sequence num is 0x00 then bytes are MessageLen (2 bytes), CRC16 (2 bytes), Flags (1 byte reserved). Defined in RFC0005'},
273
307
  'EF': {'opc': 'PARAMS', 'title': 'Response to request for node parameters', 'format': 'Para1_7', 'minpri': 3, 'comment': 'A node response while in ‘setup’ mode for its parameter string. Reply to (RQNP)'},
274
308
  'F0': {'opc': 'ACON3', 'title': 'Accessory ON', 'format': 'NN,EnHigh_EnLow,Byte1,Byte2,Byte3', 'minpri': 3, 'comment': 'Indicates an ON event using the full event number of 4 bytes with three additional data bytes.'},
275
309
  'F1': {'opc': 'ACOF3', 'title': 'Accessory OFF', 'format': 'NN,EnHigh_EnLow,Byte1,Byte2,Byte3', 'minpri': 3, 'comment': 'Indicates an OFF event using the full event number of 4 bytes with three additional data bytes.'},
276
310
  'F2': {'opc': 'ENRSP', 'title': 'Response to request to read node events', 'format': 'NN,En3_0,EnIndex', 'minpri': 3, 'comment': 'Where the NN is that of the sending node. EN3 to EN0 are the four bytes of the stored event. EN# is the index of the event within the sending node. This is a response to either 57 (NERD) or 72 (NENRD)'},
277
311
  'F3': {'opc': 'ARON3', 'title': 'Acessory Response Event', 'format': 'NN,EnHigh_EnLow,Byte1,Byte2,Byte3', 'minpri': 3, 'comment': 'Indicates an ‘ON’ response event with three added data bytes. A response event is a reply to a status request (AREQ) without producing an ON or OFF event.'},
278
312
  'F4': {'opc': 'AROF3', 'title': 'Acessory Response Event', 'format': 'NN,EnHigh_EnLow,Byte1,Byte2,Byte3', 'minpri': 3, 'comment': 'Indicates an ‘ON’ response event with three added data bytes. A response event is a reply to a status request (AREQ) without producing an ON or OFF event.'},
279
- 'F5': {'opc': 'EVLRNI', 'title': 'Teach and event in learn mode using event indexing', 'format': 'NN,EnHigh_EnLow,EnIndex,EvIndex,EvVal', 'minpri': 3, 'comment': 'Sent by a configuration tool to a node in learn mode to teach it an event. The event index must be known. Also teaches it the associated event variables.(EVs). This command is repeated for each EV required.'},
313
+ 'F5': {'opc': 'EVLRNI', 'title': 'Teach and event in learn mode using event indexing', 'format': 'NN,EnHigh_EnLow,EnIndex,EvIndex,EvVal', 'minpri': 3, 'comment': 'Sent by a configuration tool to a node in learn mode to teach it an event. The event index must be known. Also teaches it the associated event variables.(EVs). This command is repeated for each EV required. VLCB allow zero events and zero EVid, also return GRSP.'},
280
314
  'F6': {'opc': 'ACDAT', 'title': 'Accessory node data event', 'format': 'NN,Byte1,Byte2,Byte3,Byte4,Byte5', 'minpri': 3, 'comment': 'Indicates an event from this node with 5 bytes of data. For example, this can be used to send the 40 bits of an RFID tag. There is no event number in order to allow space for 5 bytes of data in the packet, so there can only be one data event per node.'},
281
315
  'F7': {'opc': 'ARDAT', 'title': 'Accessory node data response', 'format': 'NN,Byte1,Byte2,Byte3,Byte4,Byte5', 'minpri': 3, 'comment': 'Indicates a node data response. A response event is a reply to a status request (RQDAT) without producing a new data event.'},
282
316
  'F8': {'opc': 'ASON3', 'title': 'Accessory Short ON', 'format': 'NN,DNHigh_DNLow,Byte1,Byte2,Byte3', 'minpri': 3, 'comment': 'Indicates an ON event using the short event number of 2 LS bytes with three added data bytes.'},
283
317
  'F9': {'opc': 'ASOF3', 'title': 'Accessory Short OFF', 'format': 'NN,DNHigh_DNLow,Byte1,Byte2,Byte3', 'minpri': 3, 'comment': 'Indicates an OFF event using the short event number of 2 LS bytes with three added data bytes.'},
284
318
  'FA': {'opc': 'DDES', 'title': 'Device data event (short mode)', 'format': 'DNHigh_DNLow,Byte1,Byte2,Byte3,Byte4,Byte5', 'minpri': 3, 'comment': 'Function is the same as F6 but uses device addressing so can relate data to a device attached to a node. e.g. one of several RFID readers attached to a single node.'},
285
- 'FB': {'opc': 'DDRS', 'title': 'Device data response (short mode)', 'format': 'DNHigh_DNLow,Byte1,Byte2,Byte3,Byte4,Byte5', 'minpri': 3, 'comment': "The response to a request for data from a device. (0x5B)"},
319
+ 'FB': {'opc': 'DDRS', 'title': 'Device data response (short mode)', 'format': 'DNHigh_DNLow,Byte1,Byte2,Byte3,Byte4,Byte5', 'minpri': 3, 'comment': 'The response to a request for data from a device. (0x5B)'},
320
+ 'FC': {'opc': 'DDWS', 'title': 'Write data', 'format': 'DNHigh_DNLow,byte1,byte2,byte3,byte4,byte5', 'minpri': 0, 'comment': 'Used to write data to a device such as an RFID tag. For RC522 byte1 should be 0.'},
286
321
  'FD': {'opc': 'ARSON3', 'title': 'Accessory Short Response Event', 'format': 'NN,DNHigh_DNLow,Byte1,Byte2,Byte3', 'minpri': 3, 'comment': "Indicates an ON response event with with three added data bytes. A response event is a reply to a status request (ASRQ) without producing an ON or OFF event."},
287
322
  'FE': {'opc': 'ARSOF3', 'title': 'Accessory Short Response Event', 'format': 'NN,DNHigh_DNLow,Byte1,Byte2,Byte3', 'minpri': 3, 'comment': "Indicates an OFF response event with with three added data bytes. A response event is a reply to a status request (ASRQ) without producing an ON or OFF event."},
288
323
  'FF': {'opc': 'EXTC6', 'title': 'Extended op-code with 6 data bytes', 'format': 'ExtOpc,Byte1,Byte2,Byte3,Byte4,Byte5,Byte6', 'minpri': 3, 'comment': 'Used if the basic set of 32 OPCs is not enough. Allows an additional 256 OPCs'}
@@ -341,7 +376,19 @@ class VLCBOpcode:
341
376
  "En3_0": [8, "hex"], # 4 bytes of stored event
342
377
  "EVSPC": [2, "num"], # Amount of space available for events
343
378
  "ErrCode": [2, "hex"], # Short 1 byte error code
344
- "Error": [4, "hex"] # Error code
379
+ "Error": [4, "hex"], # Error code
380
+ "ModeCmd": [2, "num"], # New VLCB mode command
381
+ "ServiceIndex": [2, "hex"], # New VLCB Index of services
382
+ "DiagCode": [2, "hex"], # New VLCB Diagnostic data code
383
+ "DiagVal": [4, "hex"], # New VLCB Diagnostic data value
384
+ "Sequence": [2, "num"], # New VLCB Sequence number (also RFC0005 SequenceNum)
385
+ "StatusBits": [2, "hex"], # New VLCB StatusBits
386
+ "ServiceType": [2, "hex"], # New VLCB Service Type
387
+ "Version": [2, "num"], # New VLCB Version of service definition
388
+ "Opcode": [2, "hex"], # New VLCB Requested Opcode (in response)
389
+ "Result": [2, "hex"], # New VLCB Result from GRSP
390
+ "DataCode": [2, "hex"], # Used in CABDAT meaning of next 3 bytes
391
+ "StreamID": [2, "num"] # StreamID must be unique for the layout
345
392
  }
346
393
 
347
394
  # Accessory Codes - provided for convenient lookup
@@ -368,6 +415,44 @@ class VLCBOpcode:
368
415
  ]
369
416
  }
370
417
 
418
+ # DCC error codes as byte string lookup
419
+ dcc_error_codes = {
420
+ '01': 'Loco stack full',
421
+ '02': 'Loco address taken',
422
+ '03': 'Session not present',
423
+ '04': 'Consist empty',
424
+ '05': 'Loco not found',
425
+ '06': 'CAN bus error',
426
+ '07': 'Invalid request',
427
+ '08': 'Session cancelled'
428
+ }
429
+
430
+ # CMDERR / GRSP error codes as byte string lookup
431
+ grsp_error_codes = {
432
+ '00': 'OK',
433
+ '01': 'Invalid command',
434
+ '02': 'Not in learn mode',
435
+ '03': 'Not in setup mode',
436
+ '04': 'Too many events',
437
+ '05': 'No event',
438
+ '06': 'Invalid event variable index',
439
+ '07': 'Invalid event',
440
+ '08': 'Reserved',
441
+ '09': 'Invalid parameter index',
442
+ '0A': 'Invalid node variable index',
443
+ '0B': 'Invalid event variable value',
444
+ '0C': 'Invalid node variable value',
445
+ '0D': 'Other in learn mode',
446
+ 'FA': 'Invalid mode',
447
+ 'FB': 'Invalid command parameter',
448
+ 'FC': 'Invalid service',
449
+ 'FD': 'Invalid diagnostic',
450
+ 'FE': 'Unknown NVM type',
451
+ 'FF': 'Reserved'
452
+ }
453
+
454
+
455
+
371
456
  # Shorten op-code (remove extra characters)
372
457
  # Used to allow methods to be used if mnemonic is included in op-code
373
458
  # Or you could pass the entire data section
File without changes
File without changes