001package jmri.jmrix.can.adapters.gridconnect.canrs; 002 003import jmri.jmrix.can.CanMessage; 004import jmri.jmrix.can.adapters.gridconnect.GridConnectMessage; 005 006/** 007 * Class for messages for a MERG CAN-RS hardware adapter. 008 * <p> 009 * The MERG variant of the GridConnect protocol encodes messages as an ASCII 010 * string of up to 24 characters of the form: :ShhhhNd0d1d2d3d4d5d6d7; hhhh is 011 * the two byte (11 useful bits) header The S indicates a standard CAN frame 012 * :XhhhhhhhhNd0d1d2d3d4d5d6d7; The X indicates an extended CAN frame Strict 013 * Gridconnect protocol allows a variable number of header characters, e.g., a 014 * header value of 0x123 could be encoded as S123 rather than S0123 or 015 * X00000123. We choose a fixed number, either 4 or 8 bytes when sending 016 * GridConnectMessages to keep MERG CAN-RS/USB adapters happy. The 11 bit 017 * standard header is left justified in these 4 bytes. The 29 bit standard 018 * header is sent as {@code <11 bit SID><0><1><0>< 18 bit EID>} 019 * N or R indicates a normal or remote frame, in position 6 or 10 d0 - d7 are 020 * the (up to) 8 data bytes 021 * <p> 022 * 023 * @author Andrew Crosland Copyright (C) 2008 024 */ 025public class MergMessage extends GridConnectMessage { 026 027 // Creates a new instance of GridConnectMessage 028 public MergMessage() { 029 super(); 030 } 031 032 public MergMessage(CanMessage m) { 033 this(); 034 035 // Standard or extended frame 036 setExtended(m.isExtended()); 037 038 // Copy the header 039 MergMessage.this.setHeader(m.getHeader()); 040 041 // Normal or Remote frame? 042 MergMessage.this.setRtr(m.isRtr()); 043 044 // Data payload 045 for (int i = 0; i < m.getNumDataElements(); i++) { 046 MergMessage.this.setByte(m.getElement(i), i); 047 } 048 // Terminator 049 int offset = isExtended() ? 11 : 7; // differs here from superclass 050 setElement(offset + m.getNumDataElements() * 2, ';'); 051 setNumDataElements(offset + 1 + m.getNumDataElements() * 2); 052 log.debug("encoded as {}", MergMessage.this); 053 } 054 055 /** 056 * Set the header in MERG format 057 * 058 * @param header A valid CAN header value 059 */ 060 @Override 061 public void setHeader(int header) { 062 int munged; 063 if (isExtended()) { 064 munged = ((header << 3) & 0xFFE00000) | 0x80000 | (header & 0x3FFFF); 065 log.debug("Extended header is {}, munged header is {}", header, munged); 066 super.setHeader(munged); 067 } else { 068 // 11 header bits are left justified 069 munged = header << 5; 070 log.debug("Standard header is {}, munged header is {}", header, munged); 071 // Can't use super() as we want to send 4 digits 072 setHexDigit((munged >> 12) & 0xF, 2); 073 setHexDigit((munged >> 8) & 0xF, 3); 074 setHexDigit((munged >> 4) & 0xF, 4); 075 setHexDigit(0, 5); 076 } 077 } 078 079 @Override 080 public void setRtr(boolean rtr) { 081 int offset = isExtended() ? 10 : 6; 082 setElement(offset, rtr ? 'R' : 'N'); 083 } 084 085 /** 086 * Set a byte as two ASCII hex digits 087 * <p> 088 * Data bytes are encoded as two ASCII hex digits starting at byte 7 of the 089 * message. 090 * 091 * @param val the value to set, must be in range 0 - 255 092 * @param n the index of the byte to be set 093 */ 094 @Override 095 public void setByte(int val, int n) { 096 if ((n >= 0) && (n <= 7)) { 097 int index = n * 2 + (isExtended() ? 11 : 7); // differs here from superclass 098 if ((val < 0) || (val > 255)) { 099 log.error("Byte value {} out of range 0-255 for MergMessage data payload", val, new IllegalArgumentException()); 100 val = 0; 101 } 102 setHexDigit((val / 16) & 0xF, index++); 103 setHexDigit(val & 0xF, index); 104 return; 105 } 106 log.error("Byte Index {} out of range 0-7 for MergMessage data payload", n, new IllegalArgumentException()); 107 } 108 109 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MergMessage.class); 110}