001package jmri.jmrix.can.adapters.lawicell; 002 003import jmri.jmrix.AbstractMRMessage; 004import jmri.jmrix.can.CanMessage; 005// import org.slf4j.Logger; 006// import org.slf4j.LoggerFactory; 007 008/** 009 * Class for messages for a LAWICELL CAN hardware adapter. 010 * <p> 011 * The Lawicell adapter protocol encodes messages as an ASCII string of up to 24 012 * characters of the form: tiiildd...[CR] Tiiiiiiiildd...[CR] The t or T 013 * indicates a standard or extended CAN frame iiiiiiii is the header as hex 014 * digits l is the number of bytes of data dd are the (up to) 8 data bytes 015 * <p> 016 * RTR Extended frames start with an R, RTR standard frames with r. 017 * 018 * @author Andrew Crosland Copyright (C) 2008 019 * @author Bob Jacobsen Copyright (C) 2008, 2009 020 * @author Steve Young Copyright (C) 2022 ( added RTR Can Frame support ) 021*/ 022public class Message extends AbstractMRMessage { 023 024 static final int MAXLEN = 27; 025 private boolean _isRTR = false; 026 027 public Message() { 028 _nDataChars = MAXLEN; 029 _dataChars = new int[_nDataChars]; 030 } 031 032 public Message(CanMessage m) { 033 this(); 034 addCanMessage(m); 035 } 036 037 private void addCanMessage(CanMessage m){ 038 039 // Standard or extended frame? 040 setExtended(m.isExtended()); 041 042 // CAN header 043 int index = 1; 044 index = setHeader(m.getHeader(), index); 045 046 setRtr(m.isRtr()); 047 048 // length 049 setHexDigit(m.getNumDataElements(), index++); 050 051 // Data payload 052 for (int i = 0; i < m.getNumDataElements(); i++) { 053 setHexDigit((m.getElement(i) >> 4) & 0x0F, index++); 054 setHexDigit(m.getElement(i) & 0x0F, index++); 055 } 056 // Terminator 057 setElement(index++, 0x0D); 058 setNumDataElements(index); 059 } 060 061 // accessors to the bulk data 062 @Override 063 public int getNumDataElements() { 064 return _nDataChars; 065 } 066 067 public void setNumDataElements(int n) { 068 _nDataChars = (n <= MAXLEN) ? n : MAXLEN; 069 } 070 071 @Override 072 public int getElement(int n) { 073 return _dataChars[n]; 074 } 075 076 @Override 077 public void setElement(int n, int v) { 078 _dataChars[n] = v; 079 } 080 081 public void setData(int[] d) { 082 int len = (d.length <= MAXLEN) ? d.length : MAXLEN; 083 System.arraycopy(d, 0, _dataChars, 0, len); 084 } 085 086 public void setExtended(boolean extended) { 087 if (extended) { // extended 088 setElement(0, ( isRtrSet() ? 'R': 'T')); 089 } else { 090 // standard 091 setElement(0, ( isRtrSet() ? 'r': 't')); 092 } 093 } 094 095 public boolean isExtended() { 096 return getElement(0) == 'T' || getElement(0) == 'R'; 097 } 098 099 public void setRtr(boolean isrtr){ 100 _isRTR = isrtr; 101 setExtended(isExtended()); // reset element 0. 102 } 103 104 public boolean isRtrSet(){ 105 return _isRTR; 106 } 107 108 /** 109 * Set the CAN header as ASCII hex digits. 110 * Handles extended/standard internally. 111 * 112 * @param header A valid CAN header value 113 * @param index start index. 114 * @return index to next bytes, after this 115 */ 116 public int setHeader(int header, int index) { 117 if (isExtended()) { 118 // extended MSB part 119 setHexDigit((header >> 28) & 0xF, index++); 120 setHexDigit((header >> 24) & 0xF, index++); 121 setHexDigit((header >> 20) & 0xF, index++); 122 setHexDigit((header >> 16) & 0xF, index++); 123 setHexDigit((header >> 12) & 0xF, index++); 124 } 125 // standard part 126 setHexDigit((header >> 8) & 0xF, index++); 127 setHexDigit((header >> 4) & 0xF, index++); 128 setHexDigit((header >> 0) & 0xF, index++); 129 130 return index; 131 } 132 133 /** 134 * Set a byte as two ASCII hex digits 135 * <p> 136 * Data bytes are encoded as two ASCII hex digits starting at byte 7 of the 137 * message. 138 * 139 * @param val the value to set 140 * @param n the index of the byte to be set 141 */ 142 public void setByte(int val, int n) { 143 if ((n >= 0) && (n <= 7)) { 144 int index = n * 2 + 7; 145 setHexDigit((val / 16) & 0xF, index++); 146 setHexDigit(val & 0xF, index); 147 } 148 } 149 150 // Set a hex digit at offset n in _dataChars 151 void setHexDigit(int val, int n) { 152 if ((val >= 0) && (val <= 15)) { 153 if (val < 10) { 154 _dataChars[n] = val + '0'; 155 } else { 156 _dataChars[n] = val - 10 + 'A'; 157 } 158 } else { 159 _dataChars[n] = '0'; 160 } 161 } 162 163 // private final static Logger log = LoggerFactory.getLogger(Message.class); 164} 165 166