001package jmri.jmrix.marklin; 002 003/** 004 * Encodes a message to a Marklin command station. 005 * <p> 006 * The {@link MarklinReply} class handles the response from the command station. 007 * Packages of length 13 are interpreted as can-bus packages: 008 * 4 bytes Can-bus-ID (BigEndian or network order), 009 * 1-byte length and 010 * 8 bytes of data, if necessary with null bytes to fill in. 011 * <p> 012 * The message ID is divided into the areas of lower priority (priority), 013 * command (command), response and hash. 014 * The communication is based on the following format: 015 * Prio - 2 +2bit 016 * Command 8 bit 017 * Resp - 1 bit 018 * Hash - 16bit 019 * DLC - 4bit (ie CAN message length) 020 * CAN message 8 BYTES 021 * Can Message Bytes 0 to 3 are the address bytes, with byte 0 High, byte 3 low 022 * @author Kevin Dickerson Copyright (C) 2001, 2008 023 */ 024public class MarklinMessage extends jmri.jmrix.AbstractMRMessage { 025 026 static int MY_UID = 0x12345678; 027 028 MarklinMessage() { 029 _dataChars = new int[13]; 030 _nDataChars = 13; 031 setBinary(true); 032 for (int i = 0; i < 13; i++) { 033 _dataChars[i] = 0x00; 034 } 035 } 036 037 // create a new one from an array 038 public MarklinMessage(int[] d) { 039 this(); 040 System.arraycopy(d, 0, _dataChars, 0, d.length); 041 } 042 043 // create a new one from a byte array, as a service 044 public MarklinMessage(byte[] d) { 045 this(); 046 for (int i = 0; i < d.length; i++) { 047 _dataChars[i] = d[i] & 0xFF; 048 } 049 } 050 051 // create a new one 052 public MarklinMessage(int i) { 053 this(); 054 } 055 056 // copy one 057 public MarklinMessage(MarklinMessage m) { 058 super(m); 059 } 060 061 // static methods to return a formatted message 062 public static MarklinMessage getEnableMain() { 063 MarklinMessage m = new MarklinMessage(); 064 m.setElement(0, MarklinConstants.SYSCOMMANDSTART & 0xFF); 065 m.setElement(1, 0x00 & 0xFF); 066 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 067 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 068 m.setElement(4, 0x05 & 0xFF); //five bytes; 069 //5, 6, 7, 8 Address but this is a global command 070 m.setElement(9, MarklinConstants.CMDGOSYS & 0xFF); //Turn main on 0x01 071 return m; 072 } 073 074 public static MarklinMessage getKillMain() { 075 MarklinMessage m = new MarklinMessage(); 076 m.setElement(0, MarklinConstants.SYSCOMMANDSTART & 0xFF); 077 m.setElement(1, 0x00 & 0xFF); 078 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 079 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 080 m.setElement(4, 0x05 & 0xFF); //five bytes; 081 //5, 6, 7, 8 Address but this is a global command 082 m.setElement(9, MarklinConstants.CMDSTOPSYS & 0xFF); //Turn main off 0x00 083 return m; 084 } 085 086 /** 087 * Generate CAN BOOT command (0xB1). 088 * <p> 089 * This command is used to invoke the bootloader update sequence 090 * for Märklin devices. According to German language forum research, 091 * this is part of the software/bootloader command range used for 092 * firmware updates and device initialization. 093 * 094 * @return MarklinMessage containing the CAN BOOT command 095 * @see <a href="https://www.stummiforum.de/t122854f7-M-rklin-CAN-Protokoll-x-B-commands-updates.html">Märklin CAN Protokoll 0x1B commands documentation</a> 096 */ 097 public static MarklinMessage getCanBoot() { 098 MarklinMessage m = new MarklinMessage(); 099 m.setElement(0, (0xB1 >> 7) & 0xFF); // Command 0xB1 high bits 100 m.setElement(1, (0xB1 << 1) & 0xFF); // Command 0xB1 low bits 101 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 102 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 103 m.setElement(4, 0x00 & 0xFF); // DLC = 0 for basic boot command 104 // Elements 5-12 are left as default 0x00 for this command 105 return m; 106 } 107 108 //static public MarklinMessage get 109 public static MarklinMessage getSetTurnout(int addr, int state, int power) { 110 MarklinMessage m = new MarklinMessage(); 111 m.setElement(0, (MarklinConstants.ACCCOMMANDSTART >> 7) & 0xFF); 112 m.setElement(1, (MarklinConstants.ACCCOMMANDSTART << 1) & 0xFF); 113 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 114 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 115 m.setElement(4, 0x06 & 0xFF); //five bytes; 116 m.setElement(MarklinConstants.CANADDRESSBYTE1, (addr >> 24) & 0xFF); 117 m.setElement(MarklinConstants.CANADDRESSBYTE2, (addr >> 16) & 0xFF); 118 m.setElement(MarklinConstants.CANADDRESSBYTE3, (addr >> 8) & 0xFF); 119 m.setElement(MarklinConstants.CANADDRESSBYTE4, (addr) & 0xFF); 120 m.setElement(9, state & 0xff); 121 m.setElement(10, power & 0xff); 122 return m; 123 } 124 125 public static MarklinMessage getQryLocoSpeed(int addr) { 126 MarklinMessage m = new MarklinMessage(); 127 m.setElement(0, (MarklinConstants.LOCOSPEED >> 7) & 0xFF); 128 m.setElement(1, (MarklinConstants.LOCOSPEED << 1) & 0xFF); 129 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 130 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 131 m.setElement(4, 0x04 & 0xFF); 132 m.setElement(MarklinConstants.CANADDRESSBYTE1, (addr >> 24) & 0xFF); 133 m.setElement(MarklinConstants.CANADDRESSBYTE2, (addr >> 16) & 0xFF); 134 m.setElement(MarklinConstants.CANADDRESSBYTE3, (addr >> 8) & 0xFF); 135 m.setElement(MarklinConstants.CANADDRESSBYTE4, (addr) & 0xFF); 136 return m; 137 } 138 139 public static MarklinMessage setLocoSpeed(int addr, int speed) { 140 MarklinMessage m = new MarklinMessage(); 141 m.setElement(0, (MarklinConstants.LOCOSPEED >> 7) & 0xFF); 142 m.setElement(1, (MarklinConstants.LOCOSPEED << 1) & 0xFF); 143 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 144 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 145 m.setElement(4, 0x06 & 0xFF); 146 m.setElement(MarklinConstants.CANADDRESSBYTE1, (addr >> 24) & 0xFF); 147 m.setElement(MarklinConstants.CANADDRESSBYTE2, (addr >> 16) & 0xFF); 148 m.setElement(MarklinConstants.CANADDRESSBYTE3, (addr >> 8) & 0xFF); 149 m.setElement(MarklinConstants.CANADDRESSBYTE4, (addr) & 0xFF); 150 m.setElement(9, (speed >> 8) & 0xff); 151 m.setElement(10, speed & 0xff); 152 return m; 153 } 154 155 public static MarklinMessage setLocoEmergencyStop(int addr) { 156 MarklinMessage m = new MarklinMessage(); 157 m.setElement(0, MarklinConstants.SYSCOMMANDSTART & 0xFF); 158 m.setElement(1, 0x00 & 0xFF); 159 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 160 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 161 m.setElement(4, 0x05 & 0xFF); //five bytes; 162 m.setElement(MarklinConstants.CANADDRESSBYTE1, (addr >> 24) & 0xFF); 163 m.setElement(MarklinConstants.CANADDRESSBYTE2, (addr >> 16) & 0xFF); 164 m.setElement(MarklinConstants.CANADDRESSBYTE3, (addr >> 8) & 0xFF); 165 m.setElement(MarklinConstants.CANADDRESSBYTE4, (addr) & 0xFF); 166 m.setElement(9, MarklinConstants.LOCOEMERGENCYSTOP & 0xFF); 167 return m; 168 } 169 170 public static MarklinMessage setLocoSpeedSteps(int addr, int step) { 171 MarklinMessage m = new MarklinMessage(); 172 m.setElement(0, MarklinConstants.SYSCOMMANDSTART & 0xFF); 173 m.setElement(1, 0x00 & 0xFF); 174 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 175 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 176 m.setElement(4, 0x05 & 0xFF); //five bytes; 177 m.setElement(MarklinConstants.CANADDRESSBYTE1, (addr >> 24) & 0xFF); 178 m.setElement(MarklinConstants.CANADDRESSBYTE2, (addr >> 16) & 0xFF); 179 m.setElement(MarklinConstants.CANADDRESSBYTE3, (addr >> 8) & 0xFF); 180 m.setElement(MarklinConstants.CANADDRESSBYTE4, (addr) & 0xFF); 181 m.setElement(9, 0x05 & 0xFF); 182 m.setElement(10, step & 0xFF); 183 return m; 184 } 185 186 public static MarklinMessage getQryLocoDirection(int addr) { 187 MarklinMessage m = new MarklinMessage(); 188 m.setElement(0, (MarklinConstants.LOCODIRECTION >> 7) & 0xFF); 189 m.setElement(1, (MarklinConstants.LOCODIRECTION << 1) & 0xFF); 190 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 191 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 192 m.setElement(4, 0x04 & 0xFF); 193 m.setElement(MarklinConstants.CANADDRESSBYTE1, (addr >> 24) & 0xFF); 194 m.setElement(MarklinConstants.CANADDRESSBYTE2, (addr >> 16) & 0xFF); 195 m.setElement(MarklinConstants.CANADDRESSBYTE3, (addr >> 8) & 0xFF); 196 m.setElement(MarklinConstants.CANADDRESSBYTE4, (addr) & 0xFF); 197 return m; 198 } 199 200 public static MarklinMessage setLocoDirection(int addr, int dir) { 201 MarklinMessage m = new MarklinMessage(); 202 m.setElement(0, (MarklinConstants.LOCODIRECTION >> 7) & 0xFF); 203 m.setElement(1, (MarklinConstants.LOCODIRECTION << 1) & 0xFF); 204 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 205 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 206 m.setElement(4, 0x05 & 0xFF); 207 m.setElement(MarklinConstants.CANADDRESSBYTE1, (addr >> 24) & 0xFF); 208 m.setElement(MarklinConstants.CANADDRESSBYTE2, (addr >> 16) & 0xFF); 209 m.setElement(MarklinConstants.CANADDRESSBYTE3, (addr >> 8) & 0xFF); 210 m.setElement(MarklinConstants.CANADDRESSBYTE4, (addr) & 0xFF); 211 m.setElement(9, dir & 0xff); 212 return m; 213 } 214 215 public static MarklinMessage getQryLocoFunction(int addr, int funct) { 216 MarklinMessage m = new MarklinMessage(); 217 m.setElement(0, (MarklinConstants.LOCOFUNCTION >> 7) & 0xFF); 218 m.setElement(1, (MarklinConstants.LOCOFUNCTION << 1) & 0xFF); 219 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 220 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 221 m.setElement(4, 0x05 & 0xFF); 222 m.setElement(MarklinConstants.CANADDRESSBYTE1, (addr >> 24) & 0xFF); 223 m.setElement(MarklinConstants.CANADDRESSBYTE2, (addr >> 16) & 0xFF); 224 m.setElement(MarklinConstants.CANADDRESSBYTE3, (addr >> 8) & 0xFF); 225 m.setElement(MarklinConstants.CANADDRESSBYTE4, (addr) & 0xFF); 226 m.setElement(9, (funct) & 0xFF); 227 return m; 228 } 229 230 public static MarklinMessage setLocoFunction(int addr, int funct, int state) { 231 MarklinMessage m = new MarklinMessage(); 232 m.setElement(0, (MarklinConstants.LOCOFUNCTION >> 7) & 0xFF); 233 m.setElement(1, (MarklinConstants.LOCOFUNCTION << 1) & 0xFF); 234 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 235 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 236 m.setElement(4, 0x06 & 0xFF); 237 m.setElement(MarklinConstants.CANADDRESSBYTE1, (addr >> 24) & 0xFF); 238 m.setElement(MarklinConstants.CANADDRESSBYTE2, (addr >> 16) & 0xFF); 239 m.setElement(MarklinConstants.CANADDRESSBYTE3, (addr >> 8) & 0xFF); 240 m.setElement(MarklinConstants.CANADDRESSBYTE4, (addr) & 0xFF); 241 m.setElement(9, funct & 0xff); 242 m.setElement(10, state & 0xff); 243 m.getAddress(); 244 return m; 245 } 246 247 public static MarklinMessage sensorPollMessage(int module) { 248 MarklinMessage m = new MarklinMessage(); 249 m.setElement(0, (MarklinConstants.FEECOMMANDSTART >> 7) & 0xFF); 250 m.setElement(1, (MarklinConstants.FEECOMMANDSTART << 1) & 0xFF); 251 m.setElement(2, MarklinConstants.HASHBYTE1 & 0xFF); 252 m.setElement(3, MarklinConstants.HASHBYTE2 & 0xFF); 253 m.setElement(4, 0x05 & 0xFF); //five bytes; 254 m.setElement(MarklinConstants.CANADDRESSBYTE1, (MY_UID >> 24) & 0xFF); 255 m.setElement(MarklinConstants.CANADDRESSBYTE2, (MY_UID >> 16) & 0xFF); 256 m.setElement(MarklinConstants.CANADDRESSBYTE3, (MY_UID >> 8) & 0xFF); 257 m.setElement(MarklinConstants.CANADDRESSBYTE4, (MY_UID) & 0xFF); 258 m.setElement(9, module & 0xFF); 259 return m; 260 } 261 262 public long getAddress() { 263 long addr = getElement(MarklinConstants.CANADDRESSBYTE1); 264 addr = (addr << 8) + getElement(MarklinConstants.CANADDRESSBYTE2); 265 addr = (addr << 8) + getElement(MarklinConstants.CANADDRESSBYTE3); 266 addr = (addr << 8) + getElement(MarklinConstants.CANADDRESSBYTE4); 267 268 return addr; 269 } 270 271 public static MarklinMessage getProgMode() { 272 return new MarklinMessage(); 273 } 274 275 public static MarklinMessage getExitProgMode() { 276 return new MarklinMessage(); 277 } 278 279 public static MarklinMessage getReadPagedCV(int cv) { //Rxxx 280 return new MarklinMessage(); 281 } 282 283 public static MarklinMessage getWritePagedCV(int cv, int val) { //Pxxx xxx 284 return new MarklinMessage(); 285 } 286 287 public static MarklinMessage getReadRegister(int reg) { //Vx 288 return new MarklinMessage(); 289 } 290 291 public static MarklinMessage getWriteRegister(int reg, int val) { //Sx xxx 292 return new MarklinMessage(); 293 } 294 295 public static MarklinMessage getReadDirectCV(int cv) { //Rxxx 296 return new MarklinMessage(); 297 } 298 299 public static MarklinMessage getWriteDirectCV(int cv, int val) { //Pxxx xxx 300 return new MarklinMessage(); 301 } 302}