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