auto-sync

This commit is contained in:
rusEfi 2015-03-06 19:06:07 -06:00
parent 2d8ed8cce2
commit 93120c4d60
8 changed files with 447 additions and 6 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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;
}
}