From 93120c4d6061f54d3c49e3a993a9774bf6b00809 Mon Sep 17 00:00:00 2001 From: rusEfi Date: Fri, 6 Mar 2015 19:06:07 -0600 Subject: [PATCH] auto-sync --- .../rusefi/binaryprotocol/BinaryProtocol.java | 62 ++++++ .../binaryprotocol/BinaryProtocolCmd.java | 84 ++++++++ .../io/src/com/rusefi/binaryprotocol/CRC.java | 4 + .../rusefi/binaryprotocol/test/CRCTest.java | 17 +- .../src/com/rusefi/io/serial/PortHolder.java | 6 +- .../rusefi/io/serial/SerialPortReader.java | 2 +- java_console/io/src/etch/util/ByteBuffer.java | 192 ++++++++++++++++++ .../io/src/etch/util/CircularByteBuffer.java | 86 ++++++++ 8 files changed, 447 insertions(+), 6 deletions(-) create mode 100644 java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java create mode 100644 java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocolCmd.java create mode 100644 java_console/io/src/etch/util/ByteBuffer.java create mode 100644 java_console/io/src/etch/util/CircularByteBuffer.java diff --git a/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java b/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java new file mode 100644 index 0000000000..73e5f7e687 --- /dev/null +++ b/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java @@ -0,0 +1,62 @@ +package com.rusefi.binaryprotocol; + +import etch.util.CircularByteBuffer; +import jssc.SerialPort; +import jssc.SerialPortException; + +/** + * (c) Andrey Belomutskiy + * 3/6/2015 + */ +public class BinaryProtocol { + private final SerialPort serialPort; + + public BinaryProtocol(SerialPort serialPort) { + + this.serialPort = serialPort; + } + + static void waitForBytes(CircularByteBuffer cbb, int count) throws InterruptedException { + System.out.println("Waiting for " + count + " byte(s)"); + synchronized (cbb) { + while (cbb.length() < count) + cbb.wait(); + } + } + + public static byte[] makePacket(byte[] command) { + byte[] packet = new byte[command.length + 6]; + + packet[0] = (byte) (command.length / 256); + packet[1] = (byte) command.length; + + int index = packet.length - 1; + System.arraycopy(command, 0, packet, 2, command.length); + int crc = CRC.crc32(command); + + for (int i = 0; i < 4; i++) { + packet[index--] = (byte) crc; + crc >>= 8; + } + return packet; + } + + public void sendQueryCommand() throws SerialPortException { + byte[] command = {'S'}; + sendCrcPacket(command); + } + + public void sendCrcPacket(byte[] command) throws SerialPortException { + byte[] packet = makePacket(command); + + serialPort.writeBytes(packet); + } + + public static int swap16(int x) { + return (((x & 0xFF) << 8) | ((x) >> 8)); + } + + public static int swap32(int x) { + return (((x) >> 24) & 0xff) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) | (((x) << 24) & 0xff000000); + } +} diff --git a/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocolCmd.java b/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocolCmd.java new file mode 100644 index 0000000000..5c79c2028f --- /dev/null +++ b/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocolCmd.java @@ -0,0 +1,84 @@ +package com.rusefi.binaryprotocol; + +import com.rusefi.io.DataListener; +import com.rusefi.io.serial.PortHolder; +import com.rusefi.io.serial.SerialPortReader; +import etch.util.CircularByteBuffer; +import jssc.SerialPort; +import jssc.SerialPortException; + +import java.io.EOFException; +import java.util.Arrays; + +/** + * (c) Andrey Belomutskiy + * 3/6/2015 + */ +public class BinaryProtocolCmd { + private static final int BUFFER_SIZE = 10000; + private static SerialPort serialPort; + + public static void main(String[] args) throws SerialPortException, InterruptedException, EOFException { + if (args.length != 1) { + System.out.println("Exactly one parameter expected"); + return; + } + + String port = args[0]; + + + serialPort = new SerialPort(port); + boolean opened = serialPort.openPort(); + if (!opened) { + System.out.println("failed to open " + port); + } + BinaryProtocol bp = new BinaryProtocol(serialPort); + + + final CircularByteBuffer cbb = new CircularByteBuffer(BUFFER_SIZE); + DataListener listener = new DataListener() { + @Override + public void onDataArrived(byte[] freshData) { + System.out.println(freshData.length + " byte(s) arrived"); + synchronized (cbb) { + if (cbb.size() - cbb.length() < freshData.length) { + System.out.println("buffer overflow not expected"); + cbb.clear(); + } + cbb.put(freshData); + cbb.notifyAll(); + } + } + }; + serialPort.addEventListener(new SerialPortReader(serialPort, listener)); + PortHolder.setupPort(serialPort, 38400); + System.out.println("Looks good"); + bp.sendQueryCommand(); + + + synchronized (cbb) { + BinaryProtocol.waitForBytes(cbb, 2); + + int packetSize = BinaryProtocol.swap16(cbb.getShort()); + System.out.println("Got packet size " + packetSize); + BinaryProtocol.waitForBytes(cbb, packetSize + 4); + byte[] packet = new byte[packetSize]; + int packetCrc; + synchronized (cbb) { + cbb.get(packet); + packetCrc = BinaryProtocol.swap32(cbb.getInt()); + } + int actualCrc = CRC.crc32(packet); + + boolean isCrcOk = actualCrc == packetCrc; + if(!isCrcOk) { + System.out.println(String.format("%x", actualCrc) + " vs " + String.format("%x", packetCrc)); + } + + System.out.println("packet " + Arrays.toString(packet) + ": crc ok=" + isCrcOk); + } + + + } + +} diff --git a/java_console/io/src/com/rusefi/binaryprotocol/CRC.java b/java_console/io/src/com/rusefi/binaryprotocol/CRC.java index 980492ffb0..75a21aa842 100644 --- a/java_console/io/src/com/rusefi/binaryprotocol/CRC.java +++ b/java_console/io/src/com/rusefi/binaryprotocol/CRC.java @@ -12,4 +12,8 @@ public class CRC { c.update(buf, 0, size); return (int) c.getValue(); } + + public static int crc32(byte[] packet) { + return crc32(packet, packet.length); + } } diff --git a/java_console/io/src/com/rusefi/binaryprotocol/test/CRCTest.java b/java_console/io/src/com/rusefi/binaryprotocol/test/CRCTest.java index 3e3cf6606d..12645bd37c 100644 --- a/java_console/io/src/com/rusefi/binaryprotocol/test/CRCTest.java +++ b/java_console/io/src/com/rusefi/binaryprotocol/test/CRCTest.java @@ -1,9 +1,13 @@ package com.rusefi.binaryprotocol.test; +import com.rusefi.binaryprotocol.BinaryProtocol; import com.rusefi.binaryprotocol.CRC; import org.junit.Test; +import java.util.Arrays; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * (c) Andrey Belomutskiy @@ -14,11 +18,20 @@ public class CRCTest { public void testCrc() { { byte[] a = {'A'}; - assertEquals(0xD3D99E8B, CRC.crc32(a, a.length)); + assertEquals(0xD3D99E8B, CRC.crc32(a)); } { byte[] a = {'S'}; - assertEquals(0x2060EFC3, CRC.crc32(a, a.length)); + assertEquals(0x2060EFC3, CRC.crc32(a)); } } + + @Test + public void testPackPacket() { + byte[] command = {'S'}; + byte[] expected = {0, 1, 0x53, 0x20, 0x60, -17, -61}; + byte[] actual = BinaryProtocol.makePacket(command); + assertTrue(Arrays.toString(expected) + " vs " + Arrays.toString(actual), + Arrays.equals(expected, actual)); + } } diff --git a/java_console/io/src/com/rusefi/io/serial/PortHolder.java b/java_console/io/src/com/rusefi/io/serial/PortHolder.java index 2670228756..3f5357516f 100644 --- a/java_console/io/src/com/rusefi/io/serial/PortHolder.java +++ b/java_console/io/src/com/rusefi/io/serial/PortHolder.java @@ -49,7 +49,7 @@ public class PortHolder { boolean opened = serialPort.openPort();//Open serial port if (!opened) FileLog.MAIN.logLine("not opened!"); - setupPort(serialPort); + setupPort(serialPort, BAUD_RATE); serialPort.addEventListener(new SerialPortReader(serialPort, listener)); } catch (SerialPortException e) { FileLog.rlog("ERROR " + e.getMessage()); @@ -81,8 +81,8 @@ public class PortHolder { return true; } - public static void setupPort(SerialPort serialPort) throws SerialPortException { - serialPort.setParams(BAUD_RATE, 8, 1, 0);//Set params. + public static void setupPort(SerialPort serialPort, int baudRate) throws SerialPortException { + serialPort.setParams(baudRate, 8, 1, 0);//Set params. int mask = SerialPort.MASK_RXCHAR; //Set the prepared mask serialPort.setEventsMask(mask); diff --git a/java_console/io/src/com/rusefi/io/serial/SerialPortReader.java b/java_console/io/src/com/rusefi/io/serial/SerialPortReader.java index b0c7067a42..3d8aec0472 100644 --- a/java_console/io/src/com/rusefi/io/serial/SerialPortReader.java +++ b/java_console/io/src/com/rusefi/io/serial/SerialPortReader.java @@ -11,7 +11,7 @@ import jssc.SerialPortException; * Date: 12/25/12 * (c) Andrey Belomutskiy */ -class SerialPortReader implements SerialPortEventListener { +public class SerialPortReader implements SerialPortEventListener { private SerialPort serialPort; private DataListener listener; diff --git a/java_console/io/src/etch/util/ByteBuffer.java b/java_console/io/src/etch/util/ByteBuffer.java new file mode 100644 index 0000000000..3cacf072be --- /dev/null +++ b/java_console/io/src/etch/util/ByteBuffer.java @@ -0,0 +1,192 @@ +/* $Id$ + * + * Copyright 2007-2008 Cisco Systems Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package etch.util; + +import java.io.EOFException; +import java.nio.BufferOverflowException; + +/** + * Byte buffer with operation to support getting and putting + * bytes. + */ +abstract public class ByteBuffer { + /** + * @return true if the buffer is empty. + */ + public boolean isEmpty() { + return length() == 0; + } + + /** + * @return true if the buffer is full. + */ + public boolean isFull() { + return length() == size(); + } + + /** + * @return the amount of data the buffer can hold. + */ + abstract public int size(); + + /** + * @return the amount of data in the buffer. + */ + abstract public int length(); + + /** + * @return the next byte from the buffer. + * @throws EOFException if the buffer is empty. + */ + abstract public byte get() throws EOFException; + + /** + * Gets bytes from the buffer to fill buf. + * + * @param buf + * @return the length of data put into buf. + */ + public int get(byte[] buf) { + return get(buf, 0, buf.length); + } + + /** + * Gets bytes from the buffer to fill buf, starting at the specified + * position for the specified length. + * + * @param buf + * @param off + * @param len + * @return the length of data put into buf. + */ + public int get(byte[] buf, int off, int len) { + if (off < 0) + throw new IllegalArgumentException("off < 0"); + + if (len < 0) + throw new IllegalArgumentException("len < 0"); + + if (off + len > buf.length) + throw new IllegalArgumentException("off+len > buf.length"); + + if (len == 0) + return 0; + + int count = 0; + try { + while (len > 0) { + buf[off] = get(); + count++; + off++; + len--; + } + } catch (EOFException e) { + // nothing to do. + } + return count; + } + + /** + * Puts a byte into the buffer. + * + * @param b + * @throws BufferOverflowException if the buffer is full + */ + abstract public void put(byte b) throws BufferOverflowException; + + /** + * Puts the bytes from buf into the buffer. + * + * @param buf + * @return the amount of data copied into the buffer. + */ + public int put(byte[] buf) { + return put(buf, 0, buf.length); + } + + /** + * Puts the bytes from buf into the buffer, starting at the specified + * position for the specified length; + * + * @param buf + * @param off + * @param len + * @return the amount of data copied into the buffer. + */ + public int put(byte[] buf, int off, int len) { + if (off < 0) + throw new IllegalArgumentException("off < 0"); + + if (len < 0) + throw new IllegalArgumentException("len < 0"); + + if (off + len > buf.length) + throw new IllegalArgumentException("off+len > buf.length"); + + if (len == 0) + return 0; + + int count = 0; + try { + while (len > 0) { + put(buf[off]); + count++; + off++; + len--; + } + } catch (BufferOverflowException e) { + // nothing to do. + } + return count; + } + + /** + * Clears the buffer. + */ + abstract public void clear(); + + /** + * @return a little-endian 32-bit integer from the buffer. + * @throws EOFException + */ + public int getInt() throws EOFException { + int b0 = get() & 255; + int b1 = get() & 255; + int b2 = get() & 255; + int b3 = get() & 255; + return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); + } + + public short getShort() throws EOFException { + int b0 = get() & 255; + int b1 = get() & 255; + return (short) (b0 | (b1 << 8)); + } + + /** + * Puts a little-endian 32-bit integer into the buffer. + * + * @param x + */ + public void putInt(int x) { + put((byte) x); + put((byte) (x >>> 8)); + put((byte) (x >>> 16)); + put((byte) (x >>> 24)); + } +} \ No newline at end of file diff --git a/java_console/io/src/etch/util/CircularByteBuffer.java b/java_console/io/src/etch/util/CircularByteBuffer.java new file mode 100644 index 0000000000..1002e81caa --- /dev/null +++ b/java_console/io/src/etch/util/CircularByteBuffer.java @@ -0,0 +1,86 @@ +/* $Id$ + * + * Copyright 2007-2008 Cisco Systems Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package etch.util; + +import java.io.EOFException; +import java.nio.BufferOverflowException; + +/** + * Description of CircularByteBuffer. + */ +public class CircularByteBuffer extends ByteBuffer { + /** + * Constructs the CircularByteBuffer. + * + * @param size + */ + public CircularByteBuffer(int size) { + this.size = size; + buf = new byte[size]; + } + + private final int size; + + private final byte[] buf; + + private int length; + + private int nextGet; + + private int nextPut; + + @Override + public int size() { + return size; + } + + @Override + public int length() { + return length; + } + + @Override + public void clear() { + length = 0; + nextGet = 0; + nextPut = 0; + } + + @Override + public byte get() throws EOFException { + if (isEmpty()) + throw new EOFException(); + + length--; + byte b = buf[nextGet++]; + if (nextGet >= size) + nextGet = 0; + return b; + } + + @Override + public void put(byte b) throws BufferOverflowException { + if (isFull()) + throw new BufferOverflowException(); + + length++; + buf[nextPut++] = b; + if (nextPut >= size) + nextPut = 0; + } +} \ No newline at end of file