RobotCore 1.0
WPILib port to raspberry Pi
Loading...
Searching...
No Matches
TwoWire.java
1
2package robotCore;
3
4import java.io.IOException;
5import java.nio.ByteBuffer;
6import java.nio.ByteOrder;
7import java.util.ArrayList;
8import java.util.Arrays;
9import java.util.Collections;
10import java.util.List;
11import java.util.concurrent.ArrayBlockingQueue;
12import java.util.concurrent.TimeUnit;
13import java.util.function.Consumer;
14
15import org.wpilib.hardware.hal.HALUtil;
16
17// import com.pi4j.io.i2c.I2CBus;
18// import com.pi4j.io.i2c.I2CDevice;
19// import com.pi4j.io.i2c.I2CFactory;
20// import com.pi4j.io.i2c.I2CFactory.UnsupportedBusNumberException;
21
22// import frc.robot.Robot;
23import robotCore.Device.Callback;
24
25public class TwoWire {
26 public static final int k_maxCommandLength = 44; // Must match the value in the microcontroller
27 /*
28 * No response commands should be in the range 1-127
29 */
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;
45 // public static final int k_initNavigator = 16;
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;
58
59 /*
60 * Response commands should be in the range 129-255
61 */
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;
71 // public static final int k_getNavigatorState = 138;
72 public static final int k_getGyroState = 138;
73 // public static final int k_getNavigatorYaw = 139;
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;
79
80 class Tracer {
81 class Item {
82 String m_name;
83 long m_time;
84
85 Item(String name, long time) {
86 m_name = name;
87 m_time = time;
88 }
89 }
90
91 long m_startTime = 0;
92 ArrayList<Item> m_list = new ArrayList<Item>();
93
94 void clearEpochs() {
95 m_list.clear();
96 m_startTime = System.nanoTime();
97 }
98
99 void addEpoch(String name) {
100 m_list.add(new Item(name, System.nanoTime()));
101 }
102
103 void printEpochs(Consumer<String> output) {
104 StringBuilder sb = new StringBuilder();
105 long prevTime = m_startTime;
106
107 sb.append("\n");
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;
111 }
112 output.accept(sb.toString());
113 }
114
115
116 }
117
118 // Tracer m_tracer = new Tracer();
119
120 /*
121 * This exception is thrown when the max retries is exceeded when
122 * sending commands to the Arduino. This probably means that
123 * communication with the Arduino is permanently impaired.
124 */
125 public static class HardwareException extends RuntimeException {
126 HardwareException(String msg) {
127 super(msg);
128 }
129 }
130
131 private class Command {
132 private int m_addr;
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; // Optional object
138
139 /*
140 * Simple command, no data
141 * Format: [size=4] [packetNo] [command] [cksum]
142 */
143 Command(int addr, int command, int responseSize) {
144 m_addr = addr;
145 m_responseSize = responseSize;
146 m_command = new byte[4];
147 m_command[0] = 4;
148 m_command[2] = (byte) command;
149 }
150
151 /*
152 * command with N one byte arguments
153 * Format: [size=4+N] [packetNo] [command] [byte1] ... [byteN-1] [cksum]
154 */
155 Command(int addr, int command, int responseSize, byte[] args, Callback callback, Object object) {
156 m_addr = addr;
157 m_responseSize = responseSize;
158 m_callback = callback;
159 m_object = object;
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];
165 }
166 }
167
168 /*
169 * command with N one byte arguments (with specified length)
170 * Format: [size=4+N] [packetNo] [command] [byte1] ... [byteN-1] [cksum]
171 */
172 Command(int addr, int command, int responseSize, byte[] args, int length, Callback callback, Object object) {
173 // Logger.log("TwoWire", 1, String.format("length=%d, args.length=%d", length,
174 // args.length));
175 m_addr = addr;
176 m_responseSize = responseSize;
177 m_callback = callback;
178 m_object = object;
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];
184 }
185 }
186
187 /*
188 * command with byte argument
189 * Format: [size=5] [packetNo] [command] [byte] [cksum]
190 */
191 Command(int addr, int command, int responseSize, byte byte1, Callback callback, Object object) {
192 m_addr = addr;
193 m_responseSize = responseSize;
194 m_callback = callback;
195 m_object = object;
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;
200 }
201
202 /*
203 * Command with a byte and 16 bit argument
204 * Format [size=7] [packetNo] [command] [byte] [16bit data] [cksum]
205 */
206 Command(int addr, int command, int responseSize, byte byte1, short value) {
207 m_addr = addr;
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;
213
214 ByteBuffer buffer = ByteBuffer.wrap(m_command, 4, m_command.length - 4);
215 buffer.order(ByteOrder.LITTLE_ENDIAN);
216 buffer.putShort(value);
217 }
218
219 /*
220 * Command with a byte and 32 bit argument
221 * Format [size=9] [packetNo] [command] [byte] [32bit data] [cksum]
222 */
223 Command(int addr, int command, int responseSize, byte byte1, int value) {
224 m_addr = addr;
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;
230
231 ByteBuffer buffer = ByteBuffer.wrap(m_command, 4, m_command.length - 4);
232 buffer.order(ByteOrder.LITTLE_ENDIAN);
233 buffer.putInt(value);
234 }
235
236 /*
237 * Command with N bytes of data
238 * Format [size=3+N+1] [packetNo] [command] [byte1] ... [byteN-1] [cksum];
239 *
240 */
241 Command(int addr, int command, byte[] bytes) {
242 m_addr = addr;
243 m_responseSize = 0;
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];
249 }
250 }
251
252 /*
253 * Command with 4 bytes of data
254 * Format [size=8] [packetNo] [command] [byte1] [byte2] [byte3] [byte4] [cksum];
255 */
256 Command(int addr, int command, int responseSize, byte byte1, byte byte2, byte byte3, byte byte4) {
257 // System.out.println(String.format("command3: byte2=%d", byte2));
258 m_addr = addr;
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;
267 }
268
269 /*
270 * Command with a byte and float arguments
271 * Format[size=9] [packetNo] [command] [byte] [float (32 bits)] [cksum]
272 */
273 Command(int addr, int command, int responseSize, byte byte1, float value) {
274 m_addr = addr;
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;
280
281 // Logger.log("TwoWire", 1, String.format("float=%f", value));
282
283 ByteBuffer buffer = ByteBuffer.wrap(m_command, 4, m_command.length - 4);
284 buffer.order(ByteOrder.LITTLE_ENDIAN);
285 buffer.putFloat(value);
286
287 // System.out.printf("v=%f\r\n", value);
288 // for (int i = 0 ; i < m_command.length ; i++)
289 // {
290 // System.out.printf("%02x ", m_command[i]);
291 // }
292 // System.out.println();
293 }
294
295 /*
296 * Command with two bytes of arguments
297 * Format [size=6] [packetNo] [command] [byte1] [byte2] [cksum]
298 */
299 Command(int addr, int command, int responseSize, byte byte1, byte byte2) {
300 m_addr = addr;
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;
307 }
308
309 Command(int addr, int command, int responseSize, int yaw, int x, int y) {
310 m_addr = addr;
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;
315
316 ByteBuffer buffer = ByteBuffer.wrap(m_command, 3, m_command.length - 3);
317 buffer.order(ByteOrder.LITTLE_ENDIAN);
318 buffer.putInt(yaw);
319 buffer.putInt(x);
320 buffer.putInt(y);
321 }
322 }
323
324
325 private class Device {
326 private int m_addr;
327 // private I2CDevice m_device;
328 private int m_packetNo = 0;
329 private long m_usedPins = 0;
330
331 private static final int k_writeDelay = 5;
332 // private static final int k_readDelay = 1;
333 private static final int k_errDelay = 10;
334 private static final int k_maxReadRetry = 20;
335 private static final int k_maxTries = 10;
336 // private static final int k_maxCommandLength = 30;
337 private static final int k_maxResponseLength = 36;
338 private static final int k_ack = 0x55;
339 private static final int k_ack2 = 0x56;
340 // private static final int k_nak = 0xcc;
341 private static final int k_nak2 = 0xcd;
342 I2CInterface m_i2c;
343
344 public Device(int addr) {
345 m_addr = addr;
346 m_i2c = new I2CInterface(addr);
347
348 // m_addr = addr;
349
350 // try {
351 // // Logger.log("TwoWire.Device", 1, String.format("getDevice(%d)", addr));
352 // m_device = m_i2cBus.getDevice(addr);
353 // } catch (IOException e) {
354 // e.printStackTrace();
355 // m_device = null;
356 // }
357 }
358
359 private byte computeCksum(byte[] data, int length) {
360 byte cksum = 0;
361 for (int i = 0; i < length; i++) {
362 cksum += data[i];
363 }
364
365 // if (data[2] == 25)
366 // {
367 // Logger.log("TwoWire", 1, String.format("cksum=%x", cksum & 0xff));
368 // }
369
370 return (cksum);
371 }
372
373 private void addCksum(byte[] data) {
374
375 data[data.length - 1] = computeCksum(data, data.length - 1);
376 }
377
378 private void sleep(long ms) {
379 try {
380 Thread.sleep(ms);
381 } catch (InterruptedException e) {
382 e.printStackTrace();
383 }
384 }
385
386 private byte[] readResponse(int responseSize) throws IOException {
387 byte[] response = new byte[k_maxResponseLength];
388
389 for (int retry = 0; retry < k_maxReadRetry; retry++) {
390 response[0] = (byte) 0xff; // in case the read fails
391
392 int ret = m_i2c.read(response, 0, responseSize);
393
394 // The Raspberry Pi doesn't actually handle clock streching properly.
395 // The CH32V003 is slow enough that it sometimes needs to stretch the clock between
396 // the address field of a read and the first data byte. As a result
397 // the Pi incorrectly reads the first byte with the high bit set.
398 // This byte is the Ack/Nak field and since we don't use the high bit
399 // we can mask it out here to get it to work for all cases.
400 response[0] &= 0x7f;
401
402 int ack = ((int) response[0]) & 0xff;
403
404 // for (int i = 0 ; i < responseSize ; i++)
405 // {
406 // System.out.printf("%02x ", response[i] & 0xff);
407 // }
408 // System.out.println("");
409
410 if (ack == k_ack) {
411 int size = response[1];
412
413 if ((size >= 3) && (response[2] == (byte) m_packetNo)) {
414 // A cksum is only if there is data present
415 if ((size == 3) || computeCksum(response, size - 1) == response[size - 1]) {
416 m_packetNo++;
417
418 return (Arrays.copyOfRange(response, 0, size)); // Packet delivered, return response
419 } else {
420 System.out.println(String.format("%d: Invalid response cksum", m_addr));
421 }
422 } else {
423 System.out.println(String.format("Invalid packet: size=%d, packetNo: %d:%d", response[1],
424 (byte) m_packetNo, ack));
425 }
426
427 System.out.println(String.format("c=%d, e=%d", m_packetCount, m_responseErrors));
428 } else if (ack == k_ack2) {
429 sleep(1);
430 } else if (ack == k_nak2) {
431 System.out.println(String.format("%d: Queue Overflow", m_packetNo));
432 sleep(k_errDelay);
433 return (null);
434 } else {
435 System.out.println(String.format("ack = %x", ack));
436 sleep(k_errDelay);
437 return (null);
438 }
439 }
440
441 // sleep(1000);
442
443 System.out.println(String.format("TwoWire: lastCommand=%d", m_lastCommand));
444 throw new HardwareException(String.format("Max read retries exceeded @ %d", m_addr));
445
446 // return(false);
447 }
448
449 int m_lastCommand = 0;
450 int m_packetCount = 0;
451 int m_packetErrors = 0;
452 int m_responseErrors = 0;
453
454 /*
455 * Packet format [size] [packet #] [command] [data...] [cksum]
456 */
457 private byte[] sendPacket(byte[] data, int responseSize) {
458 int count;
459
460 m_packetCount++;
461
462 m_lastCommand = ((int) data[2]) & 0xff;
463
464 data[1] = (byte) m_packetNo;
465
466 addCksum(data);
467
468 // if (m_lastCommand == 25)
469 // {
470 // Logger.log("TwoWire", 1, String.format("send: %d, len=%d, ck=%x", m_lastCommand,data.length, data[data.length-1] & 0xff));
471 // }
472
473 for (count = 0; count < k_maxTries; count++) {
474 try {
475 byte[] response;
476
477 // Logger.log("TwoWire", 1, String.format("write cmd: %d", data[2]));
478
479 m_i2c.write(data);
480
481 // If the command needs a response, wait a short time before the read
482 // if (data[2] < 0)
483 {
484 long waitTime = System.nanoTime() + ((data[2] < 2) ? 300000 : 50000);
485 while (System.nanoTime() < waitTime);
486 }
487
488 if ((response = readResponse(responseSize + 4)) != null) {
489 return (response);
490 }
491 Logger.log("TwoWire", 1, String.format("Response failed for %d @ %d", m_lastCommand, m_addr));
492
493 } catch (IOException e) {
494
495 Logger.log("TwoWire", 1, String.format("write IOException for %d @ %d - ", m_lastCommand, m_addr) + e);
496 }
497
498 m_packetErrors++;
499
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));
503 }
504
505 sleep(k_writeDelay);
506 }
507
508 throw new HardwareException(String.format("Max write retries exceeded @ %d", m_addr)); // Something is seriously wrong
509 }
510
511 private long getUsedPins() {
512 return (m_usedPins);
513 }
514
515 private void setUsedPin(int pin) {
516// Logger.log("TwoWire", 1, String.format("setUsedPin=%d", pin));
517 m_usedPins |= (1L << pin);
518 }
519
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;
526
527 private int getEncoderRange() {
528 if (m_encoderRange == 0) {
529 m_encoderRange = sendRequestInt(m_addr, TwoWire.k_getEncoderRange);
530 }
531
532 return m_encoderRange;
533 }
534
535 private boolean isPinValid(int pin, robotCore.Device.PinType type) {
536 long valid = 0;
537
538 switch (type) {
539 case PWMPin:
540 if (m_validPWMPins == 0) {
541 if (robotCore.Device.m_boardVersion != 3) {
542 m_validPWMPins = sendRequestInt(m_addr, TwoWire.k_getValidPWMPins);
543 // Logger.log("TwoWire", 1, String.format("validPWM=0x%x", (int) m_validPWMPins));
544 // while (true);
545 }
546 else {
547 m_validPWMPins = sendRequestLong(m_addr, TwoWire.k_getValidPWMPins);
548 }
549 }
550 valid = m_validPWMPins;
551 break;
552
553 case OutputPin:
554 if (m_validOutputPins == 0) {
555// Logger.log("TwoWire", 1, String.format("outputPin: ver=%d", robotCore.Device.m_boardVersion));
556 if (robotCore.Device.m_boardVersion == 4) {
557// Logger.log("TwoWire", 1, "outputPin: sendRequestInt");
558 m_validOutputPins = sendRequestInt(m_addr, TwoWire.k_getValidOutputPins);
559
560 }
561 else {
562// Logger.log("TwoWire", 1, "outputPin: sendRequestLong");
563 m_validOutputPins = sendRequestLong(m_addr, TwoWire.k_getValidOutputPins);
564 }
565 }
566 valid = m_validOutputPins;
567 break;
568
569 case AnalogPin:
570 if (m_validAnalogPins == 0) {
571 if (robotCore.Device.m_boardVersion != 3) {
572 m_validAnalogPins = sendRequestInt(m_addr, TwoWire.k_getValidAnalogPins);
573 }
574 else {
575 m_validAnalogPins = sendRequestLong(m_addr, TwoWire.k_getValidAnalogPins);
576 }
577 }
578 valid = m_validAnalogPins;
579 break;
580
581 case InterruptPin:
582 if (m_validInterruptPins == 0) {
583 if (robotCore.Device.m_boardVersion != 3) {
584 m_validInterruptPins = sendRequestInt(m_addr, TwoWire.k_getValidInterruptPins);
585 }
586 else {
587 m_validInterruptPins = sendRequestLong(m_addr, TwoWire.k_getValidInterruptPins);
588 }
589 }
590 valid = m_validInterruptPins;
591 break;
592
593 case InputPin:
594 if (m_validInputPins == 0) {
595 if (robotCore.Device.m_boardVersion == 4) {
596 m_validInputPins = sendRequestInt(m_addr, TwoWire.k_getValidInputPins);
597 }
598 else {
599 m_validInputPins = sendRequestLong(m_addr, TwoWire.k_getValidInputPins);
600 }
601 }
602 valid = m_validInputPins;
603 break;
604 }
605
606 return ((1L << pin) & valid) != 0;
607 }
608 }
609
610 // private I2CBus m_i2cBus;
611 private ArrayList<Device> m_devices = new ArrayList<Device>();
612 private ArrayBlockingQueue<Command> m_commands = new ArrayBlockingQueue<Command>(30);
613
614 interface RunCommand {
615 void run();
616 }
617
618 private List<RunCommand> m_runCommands = Collections.synchronizedList(new ArrayList<RunCommand>());
619 Object m_lock = new Object();
620
621 public void addRunCommand(RunCommand command) {
622// Logger.log("TwoWire", 1, "addRunCommand");
623 synchronized (m_lock) {
624 m_runCommands.add(command);
625 }
626 }
627
628 private int addCommand(Command command, byte[] data, int index) {
629 // Logger.log("TwoWire", 1, String.format("addCommand: %d, len=%d", (int)
630 // command.m_command[2], command.m_command[0]-4));
631
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];
635 }
636
637 return (index);
638 }
639
640 private Command combineCommands(Command command) {
641 if (command.m_command[2] > 0) {
642 // Can only combine commands that do not return a value
643 Command nextCommand;
644 byte[] data = new byte[k_maxCommandLength - 4];
645 int index = 1;
646 int nCommands = 0;
647 int addr = command.m_addr;
648
649 while ((nextCommand = m_commands.peek()) != null) {
650 int commandNo = nextCommand.m_command[2];
651
652 if ((commandNo < 0) || (nextCommand.m_addr != addr)) {
653 // Cannot combine commands which return a value or have different addresses
654 break;
655 }
656
657 int length = nextCommand.m_command[0] - 3; // Length of the command not including size, packetNo and
658 // chsum
659
660 if (nCommands == 0) {
661 length += command.m_command[0] - 3; // Must add the first command
662 }
663
664 if ((index + length) > data.length) {
665 // The combined command would exceed the max command length
666 break;
667 }
668 // There is room for the is new command so copy the command number and all data
669
670 m_commands.poll(); // pop the command
671
672 if (nCommands == 0) {
673 // Add the first command
674 // if (command.m_command[0] >= 30) {
675 // Logger.log("TwoWire", 1, String.format("len=%d,cmd=%d", command.m_command[0], command.m_command[2]));
676 // }
677 // System.out.println(String.format("C0:%d", command.m_command[0]));
678 index = addCommand(command, data, index);
679 nCommands++;
680 }
681 // System.out.println(String.format("c+:%d", nextCommand.m_command[0]));
682 index = addCommand(nextCommand, data, index);
683 nCommands++;
684 }
685
686 if (nCommands > 1) {
687 // Logger.log("TwoWire", 1, String.format("%d(%d): %d combined, len=%d", addr, m_commands.remainingCapacity(), nCommands, index));
688 // We have combined commands, so create a new command using this data
689 data[0] = (byte) nCommands;
690
691 // Logger.log("TwoWire", 1, String.format("CombineCommands: addr=%d,length=%d", addr, index));
692
693 command = new Command(addr, k_multipleCommands, 0, data, index, null, null);
694 }
695 }
696
697 return command;
698 }
699
700 private long m_threadId = 0;
701
702 void processCommand(Command command) {
703 // Logger.log("TwoWire", 1, String.format("processCommand: %d", command.m_command[2]));
704 Device device = getDevice(command.m_addr);
705 command.m_response = device.sendPacket(command.m_command, command.m_responseSize);
706
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);
711 } else {
712 synchronized (command) { // TODO - is this needed?
713 command.notify();
714 }
715 }
716
717 synchronized (m_keepAliveLock) {
718 m_keepAliveTime = HALUtil.getMonotonicMilliseconds();
719 }
720 }
721
722 static Object m_keepAliveLock = new Object();
723 static long m_keepAliveTime = 0;
724
725 static public long getKeepAliveTime() {
726 synchronized (m_keepAliveLock) {
727 return m_keepAliveTime;
728 }
729 }
730
731 public TwoWire() {
732 // Logger.setLogFile("TwoWireLog", "TwoWire", true);
733 Logger.setLogLevel("TwoWireLog", 5); // Turn off this logging
734 // try {
735 // m_i2cBus = I2CFactory.getInstance(I2CBus.BUS_1);
736 // } catch (UnsupportedBusNumberException | IOException e) {
737 // e.printStackTrace();
738 // }
739
740 /*
741 * Start the thread that will actually send packets
742 * This is the ONLY thread that will access the I2C bus
743 */
744 int k_runPeriod = 19; // Run commands every 20ms
745
746 new Thread(
747 new Runnable() {
748 public void run() {
749 m_threadId = Thread.currentThread().getId();
750
751 long nextRun = HALUtil.getMonotonicMilliseconds();
752
753 while (true) {
754 try {
755 Command command;
756 long dt = nextRun - HALUtil.getMonotonicMilliseconds();
757
758 if (dt <= 0) {
759 command = m_commands.poll();
760 } else {
761 command = m_commands.poll(dt, TimeUnit.MILLISECONDS);
762 }
763
764 if (command != null) {
765 if (robotCore.Device.m_boardVersion != 4) {
766 command = combineCommands(command);
767 }
768
769 processCommand(command);
770 }
771
772 if ((nextRun - HALUtil.getMonotonicMilliseconds()) <= 0) {
773 synchronized (m_lock) {
774 for (RunCommand runCommand : m_runCommands) {
775 runCommand.run();
776 }
777 }
778
779 nextRun += k_runPeriod;
780 }
781 } catch (InterruptedException e) {
782 e.printStackTrace();
783 }
784 }
785 }
786 }).start();
787 }
788
789 private Device getDevice(int addr) {
790 Device device;
791
792 for (int i = 0; i < m_devices.size(); i++) {
793 device = m_devices.get(i);
794
795 if (addr == device.m_addr) {
796 return (device);
797 }
798 }
799
800 // System.out.println(String.format("TwoWire: Adding device: %d", addr));
801 if (addr == 0) {
802 throw new HardwareException("Addr is zero");
803 }
804
805 device = new Device(addr);
806
807 m_devices.add(device);
808
809 return (device);
810 }
811
812 /*
813 * Send command, no response expected
814 */
815 private void sendCommand(Command command) {
816// Logger.log("TwoWireLog", 1, String.format("sendCommand: t=%d", Thread.currentThread().getId()));
817 try {
818 if (Thread.currentThread().getId() == m_threadId) {
819 // if (m_commands.remainingCapacity() == 0) {
820 // throw new HardwareException("Queue is full");
821 // }
822 // This is the command processing thread to process the command now
823 processCommand(command);
824 }
825 else {
826 // If this is not the thread that reads from the queue, do not fill up the queue
827 // while (m_commands.remainingCapacity() < 8) {
828 // Logger.log("TwoWire", 1,
829 // String.format("send: t=%d, s=%d", Thread.currentThread().getId(), m_commands.size()));
830 // RobotCoreBase.sleep(1);
831 // }
832 m_commands.put(command);
833 }
834 } catch (InterruptedException e) {
835 e.printStackTrace();
836 }
837 }
838
839 /*
840 * Command request, wait for response
841 */
842 private ByteBuffer sendRequest(Command command) {
843 try {
844 sendCommand(command);
845
846 if (command.m_callback == null) {
847 synchronized (command) {
848 ByteBuffer buffer;
849
850 command.wait();
851
852 // System.out.printf("%d: ", command.m_command[3] & 0xff);
853 // for (int i = 0 ; i < command.m_response.length ; i++) {
854 // System.out.printf("%02x ", command.m_response[i]);
855 // }
856 // System.out.println();
857
858 buffer = ByteBuffer.wrap(command.m_response, 3, command.m_response.length - 3);
859 buffer.order(ByteOrder.LITTLE_ENDIAN);
860
861 return (buffer);
862 }
863 }
864 } catch (InterruptedException e) {
865 e.printStackTrace();
866 }
867
868 return null;
869 }
870
871 /*
872 * Simple command, no arguments
873 */
874 public void sendCommand(int addr, int commandId) {
875 Command command = new Command(addr, commandId, 0);
876
877 sendCommand(command);
878 }
879
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);
884
885 sendCommand(command);
886 }
887 }
888
889 /*
890 * Command with a byte argument
891 */
892 public void sendCommand(int addr, int commandId, byte byte1) {
893 Command command = new Command(addr, commandId, 0, byte1, null, null);
894
895 sendCommand(command);
896 }
897
898 /*
899 * Command with a byte and a 16 bit argument
900 */
901 public void sendCommand(int addr, int commandId, byte byte1, short value) {
902 Command command = new Command(addr, commandId, 0, byte1, value);
903
904 sendCommand(command);
905 }
906
907 /*
908 * Command with a byte and a 32 bit argument
909 */
910 public void sendCommand(int addr, int commandId, byte byte1, int value) {
911 Command command = new Command(addr, commandId, 0, byte1, value);
912
913 sendCommand(command);
914 }
915
916 /*
917 * Command with n bytes of data
918 */
919 public void sendCommand(int addr, int commandId, byte[] bytes) {
920 Command command = new Command(addr, commandId, bytes);
921
922 sendCommand(command);
923 }
924
925 /*
926 * Command with 4 bytes of data
927 */
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);
930
931 sendCommand(command);
932 }
933
934 /*
935 * Command with byte and a float (32 bit) arguments
936 */
937 public void sendCommand(int addr, int commandId, byte byte1, float value) {
938 Command command = new Command(addr, commandId, 0, byte1, value);
939
940 sendCommand(command);
941 }
942
943 /*
944 * Command with two bytes as arguments
945 */
946 public void sendCommand(int addr, int commandId, byte byte1, byte byte2) {
947 Command command = new Command(addr, commandId, 0, byte1, byte2);
948
949 sendCommand(command);
950 }
951
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);
954
955 sendCommand(command);
956 }
957
958 /*
959 * Simple request, no arguments
960 * Note: the Arduino will only wait for a response if the commandId is greater
961 * than 127
962 */
963 public ByteBuffer sendRequest(int addr, int commandId, int size) {
964 return (sendRequest(new Command(addr, commandId, size)));
965 }
966
967 /*
968 * Takes N one byte arguments and returns N bytes of data
969 */
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));
972 }
973
974 /*
975 * One byte argument
976 */
977 public ByteBuffer sendRequest(int addr, int commandId, int size, byte byte1) {
978 return (sendRequest(new Command(addr, commandId, size, byte1, null, null)));
979 }
980
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));
983 }
984
985 /*
986 * Simple request, no arguments, returns byte
987 */
988 public int sendRequestByte(int addr, int commandId) {
989 ByteBuffer buffer = sendRequest(addr, commandId, 1);
990
991 return (buffer.get());
992 }
993
994 /*
995 * One byte argument, returns byte
996 */
997 public int sendRequestByte(int addr, int commandId, byte byte1) {
998 ByteBuffer buffer = sendRequest(addr, commandId, 1, byte1);
999
1000 return (buffer.get());
1001 }
1002
1003 /*
1004 * No arguments, returns int (32 bits)
1005 */
1006 public int sendRequestInt(int addr, int commandId) {
1007 ByteBuffer buffer = sendRequest(addr, commandId, 4);
1008
1009// Logger.log("TwoWire", 1, String.format("sendRequestInt: rem=%d, cap=%d, lim=%d", buffer.remaining(), buffer.capacity(), buffer.limit()));
1010
1011 return (buffer.getInt());
1012 }
1013
1014 /*
1015 * Takes N single byte arguments and returns N bytes of data
1016 */
1017 public void sendRequestBytes(int addr, int commandId, byte[] args, int responseSize, Callback callback) {
1018 // ByteBuffer buffer =
1019 sendRequest(addr, commandId, responseSize, args, callback);
1020
1021 // byte[] ret = new byte[args.length];
1022
1023 // for (int i = 0 ; i < args.length ; i++) {
1024 // ret[i] = buffer.get();
1025 // }
1026
1027 // return ret;
1028 // return null;
1029 }
1030
1031 /*
1032 * No arguments, returns long (64 bits)
1033 */
1034 public long sendRequestLong(int addr, int commandId) {
1035 ByteBuffer buffer = sendRequest(addr, commandId, 8);
1036
1037 return (buffer.getLong());
1038 }
1039
1040 /*
1041 * One byte argument, returns int (32 bits)
1042 */
1043 public int sendRequestInt(int addr, int commandId, byte byte1) {
1044 ByteBuffer buffer = sendRequest(addr, commandId, 4, byte1);
1045
1046 return (buffer.getInt());
1047 }
1048
1049 public void sendRequestInt(int addr, int commandId, byte byte1, Callback callback, Object object) {
1050 sendRequest(addr, commandId, 4, byte1, callback, object);
1051 }
1052
1053 /*
1054 * One byte argument, returns short (16 bits)
1055 */
1056 public int sendRequestShort(int addr, int commandId, byte byte1) {
1057 ByteBuffer buffer = sendRequest(addr, commandId, 2, byte1);
1058
1059 return (buffer.getShort());
1060 }
1061
1062 public boolean checkUsedPin(int addr, int pin) {
1063 Device device = getDevice(addr);
1064
1065// Logger.log("TwoWire", 1, String.format("checkPin %d=0x%x", pin, device.getUsedPins()));
1066
1067 return ((device.getUsedPins() & (1L << pin)) != 0);
1068 }
1069
1070 public void setUsedPin(int addr, int pin) {
1071 Device device = getDevice(addr);
1072
1073 device.setUsedPin(pin);
1074 }
1075
1076 public boolean isPinValid(int addr, int pin, robotCore.Device.PinType type) {
1077 Device device = getDevice(addr);
1078
1079 return device.isPinValid(pin, type);
1080 }
1081
1082 public int getEncoderRange(int addr) {
1083 Device device = getDevice(addr);
1084
1085 return device.getEncoderRange();
1086 }
1087}
void write(byte[] data)
int read(byte[] buffer, int offset, int length)
The Logger class provides a mechanism to log messages.
Definition Logger.java:54
static void log(String tag, int level, String message, boolean noLogToConsole)
Definition Logger.java:161