26 public static final int k_maxCommandLength = 44;
30 public static final int k_cmdKeepAlive = 1;
31 public static final int k_configureMotor = 2;
32 public static final int k_setMotor = 3;
33 public static final int k_configureEncoder = 4;
34 public static final int k_setMotorMode = 5;
35 public static final int k_setFeedbackDevice = 6;
36 public static final int k_setPIDFTerm = 7;
37 public static final int k_setPIDPTerm = 8;
38 public static final int k_setPIDITerm = 9;
39 public static final int k_setPIDDTerm = 10;
40 public static final int k_setPIDIZone = 11;
41 public static final int k_enable = 12;
42 public static final int k_disable = 13;
43 public static final int k_setMotorInverted = 14;
44 public static final int k_setEncoderInverted = 15;
46 public static final int k_initGyro = 16;
47 public static final int k_resetNavigator = 17;
48 public static final int k_invertNavigator = 18;
49 public static final int k_digitalWrite = 19;
50 public static final int k_createCounter = 20;
51 public static final int k_setZeroMotorPower = 21;
52 public static final int k_setPIDMinPower = 22;
53 public static final int k_setPIDWrap = 23;
54 public static final int k_setPIDDeadZone = 24;
55 public static final int k_multipleCommands = 25;
56 public static final int k_setMultipleMotors = 26;
57 public static final int k_setMotor32 = 27;
62 public static final int k_getBoardVersion = 129;
63 public static final int k_getValidOutputPins = 130;
64 public static final int k_getValidPWMPins = 131;
65 public static final int k_getMaxMotors = 132;
66 public static final int k_getValidAnalogPins = 133;
67 public static final int k_getEncoderPos = 134;
68 public static final int k_getEncoderSpeed = 135;
69 public static final int k_digitalRead = 136;
70 public static final int k_getEncoderRange = 137;
72 public static final int k_getGyroState = 138;
74 public static final int k_getGyroYaw = 139;
75 public static final int k_getDigitalCount = 140;
76 public static final int k_getMultipleEncoderPos = 141;
77 public static final int k_getValidInterruptPins = 142;
78 public static final int k_getValidInputPins = 143;
85 Item(String name,
long time) {
92 ArrayList<Item> m_list =
new ArrayList<Item>();
96 m_startTime = System.nanoTime();
99 void addEpoch(String name) {
100 m_list.add(
new Item(name, System.nanoTime()));
103 void printEpochs(Consumer<String> output) {
104 StringBuilder sb =
new StringBuilder();
105 long prevTime = m_startTime;
108 for (Item item : m_list) {
109 sb.append(String.format(
"%s,%f ms,%f ms\n", item.m_name, (item.m_time - m_startTime) / 1000000.0, (item.m_time - prevTime) / 1000000.0));
110 prevTime = item.m_time;
112 output.accept(sb.toString());
125 public static class HardwareException
extends RuntimeException {
126 HardwareException(String msg) {
131 private class Command {
133 private int m_responseSize;
134 private byte[] m_command;
135 private byte[] m_response;
136 private Callback m_callback =
null;
137 private Object m_object =
null;
143 Command(
int addr,
int command,
int responseSize) {
145 m_responseSize = responseSize;
146 m_command =
new byte[4];
148 m_command[2] = (byte) command;
155 Command(
int addr,
int command,
int responseSize,
byte[] args, Callback callback, Object
object) {
157 m_responseSize = responseSize;
158 m_callback = callback;
160 m_command =
new byte[4 + args.length];
161 m_command[0] = (byte) m_command.length;
162 m_command[2] = (byte) command;
163 for (
int i = 0; i < args.length; i++) {
164 m_command[3 + i] = args[i];
172 Command(
int addr,
int command,
int responseSize,
byte[] args,
int length, Callback callback, Object
object) {
176 m_responseSize = responseSize;
177 m_callback = callback;
179 m_command =
new byte[4 + length];
180 m_command[0] = (byte) m_command.length;
181 m_command[2] = (byte) command;
182 for (
int i = 0; i < length; i++) {
183 m_command[3 + i] = args[i];
191 Command(
int addr,
int command,
int responseSize,
byte byte1, Callback callback, Object
object) {
193 m_responseSize = responseSize;
194 m_callback = callback;
196 m_command =
new byte[4 + 1];
197 m_command[0] = (byte) m_command.length;
198 m_command[2] = (byte) command;
199 m_command[3] = byte1;
206 Command(
int addr,
int command,
int responseSize,
byte byte1,
short value) {
208 m_responseSize = responseSize;
209 m_command =
new byte[3 + 1 + 2 + 1];
210 m_command[0] = (byte) m_command.length;
211 m_command[2] = (byte) command;
212 m_command[3] = byte1;
214 ByteBuffer buffer = ByteBuffer.wrap(m_command, 4, m_command.length - 4);
215 buffer.order(ByteOrder.LITTLE_ENDIAN);
216 buffer.putShort(value);
223 Command(
int addr,
int command,
int responseSize,
byte byte1,
int value) {
225 m_responseSize = responseSize;
226 m_command =
new byte[3 + 1 + 4 + 1];
227 m_command[0] = (byte) m_command.length;
228 m_command[2] = (byte) command;
229 m_command[3] = byte1;
231 ByteBuffer buffer = ByteBuffer.wrap(m_command, 4, m_command.length - 4);
232 buffer.order(ByteOrder.LITTLE_ENDIAN);
233 buffer.putInt(value);
241 Command(
int addr,
int command,
byte[] bytes) {
244 m_command =
new byte[3 + bytes.length + 1];
245 m_command[0] = (byte) m_command.length;
246 m_command[2] = (byte) command;
247 for (
int i = 0 ; i < bytes.length ; i++) {
248 m_command[3+i] = bytes[i];
256 Command(
int addr,
int command,
int responseSize,
byte byte1,
byte byte2,
byte byte3,
byte byte4) {
259 m_responseSize = responseSize;
260 m_command =
new byte[3 + 4 + 1];
261 m_command[0] = (byte) m_command.length;
262 m_command[2] = (byte) command;
263 m_command[3] = byte1;
264 m_command[4] = byte2;
265 m_command[5] = byte3;
266 m_command[6] = byte4;
273 Command(
int addr,
int command,
int responseSize,
byte byte1,
float value) {
275 m_responseSize = responseSize;
276 m_command =
new byte[3 + 1 + 4 + 1];
277 m_command[0] = (byte) m_command.length;
278 m_command[2] = (byte) command;
279 m_command[3] = byte1;
283 ByteBuffer buffer = ByteBuffer.wrap(m_command, 4, m_command.length - 4);
284 buffer.order(ByteOrder.LITTLE_ENDIAN);
285 buffer.putFloat(value);
299 Command(
int addr,
int command,
int responseSize,
byte byte1,
byte byte2) {
301 m_responseSize = responseSize;
302 m_command =
new byte[3 + 2 + 1];
303 m_command[0] = (byte) m_command.length;
304 m_command[2] = (byte) command;
305 m_command[3] = byte1;
306 m_command[4] = byte2;
309 Command(
int addr,
int command,
int responseSize,
int yaw,
int x,
int y) {
311 m_responseSize = responseSize;
312 m_command =
new byte[4 + 12];
313 m_command[0] = (byte) m_command.length;
314 m_command[2] = (byte) command;
316 ByteBuffer buffer = ByteBuffer.wrap(m_command, 3, m_command.length - 3);
317 buffer.order(ByteOrder.LITTLE_ENDIAN);
325 private class Device {
328 private int m_packetNo = 0;
329 private long m_usedPins = 0;
331 private static final int k_writeDelay = 5;
333 private static final int k_errDelay = 10;
334 private static final int k_maxReadRetry = 20;
335 private static final int k_maxTries = 10;
337 private static final int k_maxResponseLength = 36;
338 private static final int k_ack = 0x55;
339 private static final int k_ack2 = 0x56;
341 private static final int k_nak2 = 0xcd;
344 public Device(
int addr) {
359 private byte computeCksum(
byte[] data,
int length) {
361 for (
int i = 0; i < length; i++) {
373 private void addCksum(
byte[] data) {
375 data[data.length - 1] = computeCksum(data, data.length - 1);
378 private void sleep(
long ms) {
381 }
catch (InterruptedException e) {
386 private byte[] readResponse(
int responseSize)
throws IOException {
387 byte[] response =
new byte[k_maxResponseLength];
389 for (
int retry = 0; retry < k_maxReadRetry; retry++) {
390 response[0] = (byte) 0xff;
392 int ret = m_i2c.
read(response, 0, responseSize);
402 int ack = ((int) response[0]) & 0xff;
411 int size = response[1];
413 if ((size >= 3) && (response[2] == (
byte) m_packetNo)) {
415 if ((size == 3) || computeCksum(response, size - 1) == response[size - 1]) {
418 return (Arrays.copyOfRange(response, 0, size));
420 System.out.println(String.format(
"%d: Invalid response cksum", m_addr));
423 System.out.println(String.format(
"Invalid packet: size=%d, packetNo: %d:%d", response[1],
424 (
byte) m_packetNo, ack));
427 System.out.println(String.format(
"c=%d, e=%d", m_packetCount, m_responseErrors));
428 }
else if (ack == k_ack2) {
430 }
else if (ack == k_nak2) {
431 System.out.println(String.format(
"%d: Queue Overflow", m_packetNo));
435 System.out.println(String.format(
"ack = %x", ack));
443 System.out.println(String.format(
"TwoWire: lastCommand=%d", m_lastCommand));
444 throw new HardwareException(String.format(
"Max read retries exceeded @ %d", m_addr));
449 int m_lastCommand = 0;
450 int m_packetCount = 0;
451 int m_packetErrors = 0;
452 int m_responseErrors = 0;
457 private byte[] sendPacket(
byte[] data,
int responseSize) {
462 m_lastCommand = ((int) data[2]) & 0xff;
464 data[1] = (byte) m_packetNo;
473 for (count = 0; count < k_maxTries; count++) {
484 long waitTime = System.nanoTime() + ((data[2] < 2) ? 300000 : 50000);
485 while (System.nanoTime() < waitTime);
488 if ((response = readResponse(responseSize + 4)) !=
null) {
491 Logger.
log(
"TwoWire", 1, String.format(
"Response failed for %d @ %d", m_lastCommand, m_addr));
493 }
catch (IOException e) {
495 Logger.
log(
"TwoWire", 1, String.format(
"write IOException for %d @ %d - ", m_lastCommand, m_addr) + e);
500 if ((m_packetErrors % 10) == 0) {
501 Logger.
log(
"TwoWire", 1, String.format(
"Write Retry: cmd=%d c=%d, e=%d", m_lastCommand,
502 m_packetCount, m_packetErrors));
508 throw new HardwareException(String.format(
"Max write retries exceeded @ %d", m_addr));
511 private long getUsedPins() {
515 private void setUsedPin(
int pin) {
517 m_usedPins |= (1L << pin);
520 long m_validPWMPins = 0;
521 long m_validOutputPins = 0;
522 long m_validInterruptPins = 0;
523 long m_validInputPins = 0;
524 long m_validAnalogPins = 0;
525 int m_encoderRange = 0;
527 private int getEncoderRange() {
528 if (m_encoderRange == 0) {
529 m_encoderRange = sendRequestInt(m_addr, TwoWire.k_getEncoderRange);
532 return m_encoderRange;
535 private boolean isPinValid(
int pin, robotCore.Device.PinType type) {
540 if (m_validPWMPins == 0) {
541 if (robotCore.Device.m_boardVersion != 3) {
542 m_validPWMPins = sendRequestInt(m_addr, TwoWire.k_getValidPWMPins);
547 m_validPWMPins = sendRequestLong(m_addr, TwoWire.k_getValidPWMPins);
550 valid = m_validPWMPins;
554 if (m_validOutputPins == 0) {
556 if (robotCore.Device.m_boardVersion == 4) {
558 m_validOutputPins = sendRequestInt(m_addr, TwoWire.k_getValidOutputPins);
563 m_validOutputPins = sendRequestLong(m_addr, TwoWire.k_getValidOutputPins);
566 valid = m_validOutputPins;
570 if (m_validAnalogPins == 0) {
571 if (robotCore.Device.m_boardVersion != 3) {
572 m_validAnalogPins = sendRequestInt(m_addr, TwoWire.k_getValidAnalogPins);
575 m_validAnalogPins = sendRequestLong(m_addr, TwoWire.k_getValidAnalogPins);
578 valid = m_validAnalogPins;
582 if (m_validInterruptPins == 0) {
583 if (robotCore.Device.m_boardVersion != 3) {
584 m_validInterruptPins = sendRequestInt(m_addr, TwoWire.k_getValidInterruptPins);
587 m_validInterruptPins = sendRequestLong(m_addr, TwoWire.k_getValidInterruptPins);
590 valid = m_validInterruptPins;
594 if (m_validInputPins == 0) {
595 if (robotCore.Device.m_boardVersion == 4) {
596 m_validInputPins = sendRequestInt(m_addr, TwoWire.k_getValidInputPins);
599 m_validInputPins = sendRequestLong(m_addr, TwoWire.k_getValidInputPins);
602 valid = m_validInputPins;
606 return ((1L << pin) & valid) != 0;
611 private ArrayList<Device> m_devices =
new ArrayList<Device>();
612 private ArrayBlockingQueue<Command> m_commands =
new ArrayBlockingQueue<Command>(30);
618 private List<RunCommand> m_runCommands = Collections.synchronizedList(
new ArrayList<RunCommand>());
619 Object m_lock =
new Object();
621 public void addRunCommand(
RunCommand command) {
623 synchronized (m_lock) {
624 m_runCommands.add(command);
628 private int addCommand(Command command,
byte[] data,
int index) {
632 data[index++] = command.m_command[2];
633 for (
int i = 0; i < command.m_command[0] - 4; i++) {
634 data[index++] = command.m_command[i + 3];
640 private Command combineCommands(Command command) {
641 if (command.m_command[2] > 0) {
644 byte[] data =
new byte[k_maxCommandLength - 4];
647 int addr = command.m_addr;
649 while ((nextCommand = m_commands.peek()) !=
null) {
650 int commandNo = nextCommand.m_command[2];
652 if ((commandNo < 0) || (nextCommand.m_addr != addr)) {
657 int length = nextCommand.m_command[0] - 3;
660 if (nCommands == 0) {
661 length += command.m_command[0] - 3;
664 if ((index + length) > data.length) {
672 if (nCommands == 0) {
678 index = addCommand(command, data, index);
682 index = addCommand(nextCommand, data, index);
689 data[0] = (byte) nCommands;
693 command =
new Command(addr, k_multipleCommands, 0, data, index,
null,
null);
700 private long m_threadId = 0;
702 void processCommand(Command command) {
704 Device device = getDevice(command.m_addr);
705 command.m_response = device.sendPacket(command.m_command, command.m_responseSize);
707 if (command.m_callback !=
null) {
708 ByteBuffer buffer = ByteBuffer.wrap(command.m_response, 3, command.m_response.length - 3);
709 buffer.order(ByteOrder.LITTLE_ENDIAN);
710 command.m_callback.callback(buffer, command.m_object);
712 synchronized (command) {
717 synchronized (m_keepAliveLock) {
718 m_keepAliveTime = HALUtil.getMonotonicMilliseconds();
722 static Object m_keepAliveLock =
new Object();
723 static long m_keepAliveTime = 0;
725 static public long getKeepAliveTime() {
726 synchronized (m_keepAliveLock) {
727 return m_keepAliveTime;
733 Logger.setLogLevel(
"TwoWireLog", 5);
744 int k_runPeriod = 19;
749 m_threadId = Thread.currentThread().getId();
751 long nextRun = HALUtil.getMonotonicMilliseconds();
756 long dt = nextRun - HALUtil.getMonotonicMilliseconds();
759 command = m_commands.poll();
761 command = m_commands.poll(dt, TimeUnit.MILLISECONDS);
764 if (command !=
null) {
765 if (robotCore.Device.m_boardVersion != 4) {
766 command = combineCommands(command);
769 processCommand(command);
772 if ((nextRun - HALUtil.getMonotonicMilliseconds()) <= 0) {
773 synchronized (m_lock) {
779 nextRun += k_runPeriod;
781 }
catch (InterruptedException e) {
789 private Device getDevice(
int addr) {
792 for (
int i = 0; i < m_devices.size(); i++) {
793 device = m_devices.get(i);
795 if (addr == device.m_addr) {
802 throw new HardwareException(
"Addr is zero");
805 device =
new Device(addr);
807 m_devices.add(device);
815 private void sendCommand(Command command) {
818 if (Thread.currentThread().getId() == m_threadId) {
823 processCommand(command);
832 m_commands.put(command);
834 }
catch (InterruptedException e) {
842 private ByteBuffer sendRequest(Command command) {
844 sendCommand(command);
846 if (command.m_callback ==
null) {
847 synchronized (command) {
858 buffer = ByteBuffer.wrap(command.m_response, 3, command.m_response.length - 3);
859 buffer.order(ByteOrder.LITTLE_ENDIAN);
864 }
catch (InterruptedException e) {
874 public void sendCommand(
int addr,
int commandId) {
875 Command command =
new Command(addr, commandId, 0);
877 sendCommand(command);
880 public void sendCommandToAll(
int commandId) {
881 for (
int i = 0; i < m_devices.size(); i++) {
882 Device device = m_devices.get(i);
883 Command command =
new Command(device.m_addr, commandId, 0);
885 sendCommand(command);
892 public void sendCommand(
int addr,
int commandId,
byte byte1) {
893 Command command =
new Command(addr, commandId, 0, byte1,
null,
null);
895 sendCommand(command);
901 public void sendCommand(
int addr,
int commandId,
byte byte1,
short value) {
902 Command command =
new Command(addr, commandId, 0, byte1, value);
904 sendCommand(command);
910 public void sendCommand(
int addr,
int commandId,
byte byte1,
int value) {
911 Command command =
new Command(addr, commandId, 0, byte1, value);
913 sendCommand(command);
919 public void sendCommand(
int addr,
int commandId,
byte[] bytes) {
920 Command command =
new Command(addr, commandId, bytes);
922 sendCommand(command);
928 public void sendCommand(
int addr,
int commandId,
byte byte1,
byte byte2,
byte byte3,
byte byte4) {
929 Command command =
new Command(addr, commandId, 0, byte1, byte2, byte3, byte4);
931 sendCommand(command);
937 public void sendCommand(
int addr,
int commandId,
byte byte1,
float value) {
938 Command command =
new Command(addr, commandId, 0, byte1, value);
940 sendCommand(command);
946 public void sendCommand(
int addr,
int commandId,
byte byte1,
byte byte2) {
947 Command command =
new Command(addr, commandId, 0, byte1, byte2);
949 sendCommand(command);
952 public void sendCommand(
int addr,
int commandId,
int yaw,
int x,
int y) {
953 Command command =
new Command(addr, commandId, 0, yaw, x, y);
955 sendCommand(command);
963 public ByteBuffer sendRequest(
int addr,
int commandId,
int size) {
964 return (sendRequest(
new Command(addr, commandId, size)));
970 public ByteBuffer sendRequest(
int addr,
int commandId,
int size,
byte[] args, Callback callback) {
971 return sendRequest(
new Command(addr, commandId, size, args, callback,
null));
977 public ByteBuffer sendRequest(
int addr,
int commandId,
int size,
byte byte1) {
978 return (sendRequest(
new Command(addr, commandId, size, byte1,
null,
null)));
981 public void sendRequest(
int addr,
int commandId,
int size,
byte byte1, Callback callback, Object
object) {
982 sendRequest(
new Command(addr, commandId, size, byte1, callback,
object));
988 public int sendRequestByte(
int addr,
int commandId) {
989 ByteBuffer buffer = sendRequest(addr, commandId, 1);
991 return (buffer.get());
997 public int sendRequestByte(
int addr,
int commandId,
byte byte1) {
998 ByteBuffer buffer = sendRequest(addr, commandId, 1, byte1);
1000 return (buffer.get());
1006 public int sendRequestInt(
int addr,
int commandId) {
1007 ByteBuffer buffer = sendRequest(addr, commandId, 4);
1011 return (buffer.getInt());
1017 public void sendRequestBytes(
int addr,
int commandId,
byte[] args,
int responseSize, Callback callback) {
1019 sendRequest(addr, commandId, responseSize, args, callback);
1034 public long sendRequestLong(
int addr,
int commandId) {
1035 ByteBuffer buffer = sendRequest(addr, commandId, 8);
1037 return (buffer.getLong());
1043 public int sendRequestInt(
int addr,
int commandId,
byte byte1) {
1044 ByteBuffer buffer = sendRequest(addr, commandId, 4, byte1);
1046 return (buffer.getInt());
1049 public void sendRequestInt(
int addr,
int commandId,
byte byte1, Callback callback, Object
object) {
1050 sendRequest(addr, commandId, 4, byte1, callback,
object);
1056 public int sendRequestShort(
int addr,
int commandId,
byte byte1) {
1057 ByteBuffer buffer = sendRequest(addr, commandId, 2, byte1);
1059 return (buffer.getShort());
1062 public boolean checkUsedPin(
int addr,
int pin) {
1063 Device device = getDevice(addr);
1067 return ((device.getUsedPins() & (1L << pin)) != 0);
1070 public void setUsedPin(
int addr,
int pin) {
1071 Device device = getDevice(addr);
1073 device.setUsedPin(pin);
1076 public boolean isPinValid(
int addr,
int pin, robotCore.Device.PinType type) {
1077 Device device = getDevice(addr);
1079 return device.isPinValid(pin, type);
1082 public int getEncoderRange(
int addr) {
1083 Device device = getDevice(addr);
1085 return device.getEncoderRange();