001package jmri.jmrix.can.adapters.gridconnect.can2usbino; 002 003import jmri.jmrix.can.CanMessage; 004import jmri.jmrix.can.adapters.gridconnect.GridConnectMessage; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008/** 009 * Class for GridConnectDoubled messages for a CAN hardware adapter. 010 * <p> 011 * The GridConnect protocol encodes messages as an ASCII string of up to 24 012 * characters of the form: :ShhhhNd0d1d2d3d4d5d6d7; The S indicates a standard 013 * CAN frame :XhhhhhhhhNd0d1d2d3d4d5d6d7; The X indicates an extended CAN frame 014 * hhhh is the two byte header N or R indicates a normal or remote frame, in 015 * position 6 or 10 d0 - d7 are the (up to) 8 data bytes 016 * <p> 017 * On transmit, this is doubled and starts with an "!" character. 018 * 019 * @author Andrew Crosland Copyright (C) 2012 020 * @author Andrew Crosland Copyright (C) 2008 021 */ 022public class GridConnectDoubledMessage extends GridConnectMessage { 023 024 // Creates a new instance of GridConnectDoubledMessage 025 public GridConnectDoubledMessage() { 026 _nDataChars = 28; 027 _dataChars = new int[_nDataChars]; 028 GridConnectDoubledMessage.this.setElement(0, '!'); 029 } 030 031 public GridConnectDoubledMessage(CanMessage m) { 032 this(); 033 addCanMessage(m); 034 } 035 036 private void addCanMessage(CanMessage m) { 037 // Standard or extended frame 038 setExtended(m.isExtended()); 039 040 // Copy the header 041 setHeader(m.getHeader()); 042 043 // Normal or Remote frame? 044 setRtr(m.isRtr()); 045 046 // Data payload 047 for (int i = 0; i < m.getNumDataElements(); i++) { 048 setByte(m.getElement(i), i); 049 } 050 // Terminator 051 int offset = isExtended() ? 11 : 6; 052 setElement(offset + m.getNumDataElements() * 2, ';'); 053 setNumDataElements(offset + 1 + m.getNumDataElements() * 2); 054 log.debug("encoded as {}", this.toString()); 055 } 056 057 // accessors to the bulk data 058 @Override 059 public int getNumDataElements() { 060 return _nDataChars * 2; 061 } 062 063 @Override 064 public void setNumDataElements(int n) { 065 _nDataChars = (n <= 28) ? n : 28; 066 } 067 068 @Override 069 public int getElement(int n) { 070 return _dataChars[n / 2]; 071 } 072 073 @Override 074 public void setElement(int n, int v) { 075 _dataChars[n] = v; 076 } 077 078 @Override 079 public void setData(int[] d) { 080 int len = (d.length <= 24) ? d.length : 24; 081 System.arraycopy(d, 0, _dataChars, 0, len); 082 } 083 084 @Override 085 public void setExtended(boolean extended) { 086 // Standard or extended frame 087 this.extended = extended; 088 if (extended) { 089 setElement(1, 'X'); 090 } else { 091 setElement(1, 'S'); 092 } 093 } 094 095 private boolean extended; 096 097 @Override 098 public boolean isExtended() { 099 return extended; 100 } 101 102 /** 103 * Set the header 104 * 105 * @param header A valid CAN header value 106 */ 107 @Override 108 public void setHeader(int header) { 109 if (isExtended()) { 110 setHexDigit((header >> 28) & 0xF, 2); 111 setHexDigit((header >> 24) & 0xF, 3); 112 setHexDigit((header >> 20) & 0xF, 4); 113 setHexDigit((header >> 16) & 0xF, 5); 114 setHexDigit((header >> 12) & 0xF, 6); 115 setHexDigit((header >> 8) & 0xF, 7); 116 setHexDigit((header >> 4) & 0xF, 8); 117 setHexDigit(header & 0xF, 9); 118 } else { 119 setHexDigit((header >> 8) & 0xF, 2); 120 setHexDigit((header >> 4) & 0xF, 3); 121 setHexDigit(header & 0xF, 4); 122 } 123 } 124 125 @Override 126 public void setRtr(boolean rtr) { 127 int offset = isExtended() ? 10 : 5; 128 setElement(offset, rtr ? 'R' : 'N'); 129 } 130 131 /** 132 * Set a byte as two ASCII hex digits 133 * <p> 134 * Data bytes are encoded as two ASCII hex digits starting at byte 7 of the 135 * message. 136 * 137 * @param val the value to set 138 * @param n the index of the byte to be set 139 */ 140 @Override 141 public void setByte(int val, int n) { 142 if ((n >= 0) && (n <= 7)) { 143 int index = n * 2 + (isExtended() ? 11 : 6); 144 setHexDigit((val / 16) & 0xF, index++); 145 setHexDigit(val & 0xF, index); 146 } 147 } 148 149 // Set a hex digit at offset n in _dataChars 150 @Override 151 protected 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(GridConnectDoubledMessage.class); 164 165}