From bc2b6b71a8fc3d8b2770bda638f0e9d997627a36 Mon Sep 17 00:00:00 2001 From: rusefillc Date: Sat, 18 Dec 2021 09:26:15 -0500 Subject: [PATCH] live data for wastegate and launch control #3588 --- .../macfaq/io/LittleEndianOutputStream.java | 294 ++++++++++++++++++ .../main/java/com/rusefi/config/Field.java | 37 ++- .../com/rusefi/config/test/FieldTest.java | 48 ++- 3 files changed, 362 insertions(+), 17 deletions(-) create mode 100644 java_console/inifile/src/main/java/com/macfaq/io/LittleEndianOutputStream.java diff --git a/java_console/inifile/src/main/java/com/macfaq/io/LittleEndianOutputStream.java b/java_console/inifile/src/main/java/com/macfaq/io/LittleEndianOutputStream.java new file mode 100644 index 0000000000..3c06319dd6 --- /dev/null +++ b/java_console/inifile/src/main/java/com/macfaq/io/LittleEndianOutputStream.java @@ -0,0 +1,294 @@ +/* + * @(#)LittleEndianOutputStream.java 1.0.1 99/05/19 + * + * Copyright 1998, 1999 Elliotte Rusty Harold + * + */ + +package com.macfaq.io; + +import java.io.*; + +/** + * A little endian output stream writes primitive Java numbers + * and characters to an output stream in a little endian format. + * The standard java.io.DataOutputStream class which this class + * imitates uses big-endian integers. + * + * @author Elliotte Rusty Harold + * @version 1.0.1, 19 May 1999 + * @see com.macfaq.io.LittleEndianInputStream + * @see java.io.DataOutputStream + */ +public class LittleEndianOutputStream extends FilterOutputStream { + + /** + * The number of bytes written so far to the little endian output stream. + */ + protected int written; + + /** + * Creates a new little endian output stream and chains it to the + * output stream specified by the out argument. + * + * @param out the underlying output stream. + * @see java.io.FilterOutputStream#out + */ + public LittleEndianOutputStream(OutputStream out) { + super(out); + } + + /** + * Writes the specified byte value to the underlying output stream. + * + * @param b the byte value to be written. + * @exception IOException if the underlying stream throws an IOException. + */ + public synchronized void write(int b) throws IOException { + out.write(b); + written++; + } + + /** + * Writes length bytes from the specified byte array + * starting at offset to the underlying output stream. + * + * @param data the data. + * @param offset the start offset in the data. + * @param length the number of bytes to write. + * @exception IOException if the underlying stream throws an IOException. + */ + public synchronized void write(byte[] data, int offset, int length) + throws IOException { + out.write(data, offset, length); + written += length; + } + + + /** + * Writes a boolean to the underlying output stream as + * a single byte. If the argument is true, the byte value 1 is written. + * If the argument is false, the byte value 0 in written. + * + * @param b the boolean value to be written. + * @exception IOException if the underlying stream throws an IOException. + */ + public void writeBoolean(boolean b) throws IOException { + + if (b) this.write(1); + else this.write(0); + + } + + /** + * Writes out a byte to the underlying output stream + * + * @param b the byte value to be written. + * @exception IOException if the underlying stream throws an IOException. + */ + public void writeByte(int b) throws IOException { + out.write(b); + written++; + } + + /** + * Writes a two byte short to the underlying output stream in + * little endian order, low byte first. + * + * @param s the short to be written. + * @exception IOException if the underlying stream throws an IOException. + */ + public void writeShort(int s) throws IOException { + + out.write(s & 0xFF); + out.write((s >>> 8) & 0xFF); + written += 2; + + } + + /** + * Writes a two byte char to the underlying output stream + * in little endian order, low byte first. + * + * @param c the char value to be written. + * @exception IOException if the underlying stream throws an IOException. + */ + public void writeChar(int c) throws IOException { + + out.write(c & 0xFF); + out.write((c >>> 8) & 0xFF); + written += 2; + + } + + /** + * Writes a four-byte int to the underlying output stream + * in little endian order, low byte first, high byte last + * + * @param i the int to be written. + * @exception IOException if the underlying stream throws an IOException. + */ + public void writeInt(int i) throws IOException { + + out.write(i & 0xFF); + out.write((i >>> 8) & 0xFF); + out.write((i >>> 16) & 0xFF); + out.write((i >>> 24) & 0xFF); + written += 4; + + } + + /** + * Writes an eight-byte long to the underlying output stream + * in little endian order, low byte first, high byte last + * + * @param l the long to be written. + * @exception IOException if the underlying stream throws an IOException. + */ + public void writeLong(long l) throws IOException { + + out.write((int) l & 0xFF); + out.write((int) (l >>> 8) & 0xFF); + out.write((int) (l >>> 16) & 0xFF); + out.write((int) (l >>> 24) & 0xFF); + out.write((int) (l >>> 32) & 0xFF); + out.write((int) (l >>> 40) & 0xFF); + out.write((int) (l >>> 48) & 0xFF); + out.write((int) (l >>> 56) & 0xFF); + written += 8; + + } + + /** + * Writes a 4 byte Java float to the underlying output stream in + * little endian order. + * + * @param f the float value to be written. + * @exception IOException if an I/O error occurs. + */ + public final void writeFloat(float f) throws IOException { + + this.writeInt(Float.floatToIntBits(f)); + + } + + /** + * Writes an 8 byte Java double to the underlying output stream in + * little endian order. + * + * @param d the double value to be written. + * @exception IOException if an I/O error occurs. + */ + public final void writeDouble(double d) throws IOException { + + this.writeLong(Double.doubleToLongBits(d)); + + } + + /** + * Writes a string to the underlying output stream as a sequence of + * bytes. Each character is written to the data output stream as + * if by the writeByte() method. + * + * @param s the String value to be written. + * @exception IOException if the underlying stream throws an IOException. + * @see java.io.LittleEndianOutputStream#writeByte(int) + * @see java.io.LittleEndianOutputStream#out + */ + public void writeBytes(String s) throws IOException { + + int length = s.length(); + for (int i = 0; i < length; i++) { + out.write((byte) s.charAt(i)); + } + written += length; + } + + /** + * Writes a string to the underlying output stream as a sequence of + * characters. Each character is written to the data output stream as + * if by the writeChar method. + * + * @param s a String value to be written. + * @exception IOException if the underlying stream throws an IOException. + * @see java.io.LittleEndianOutputStream#writeChar(int) + * @see java.io.LittleEndianOutputStream#out + */ + public void writeChars(String s) throws IOException { + + int length = s.length(); + for (int i = 0; i < length; i++) { + int c = s.charAt(i); + out.write(c & 0xFF); + out.write((c >>> 8) & 0xFF); + } + written += length * 2; + + } + + /** + * Writes a string of no more than 65,535 characters + * to the underlying output stream using UTF-8 + * encoding. This method first writes a two byte short + * in big endian order as required by the + * UTF-8 specification. This gives the number of bytes in the + * UTF-8 encoded version of the string, not the number of characters + * in the string. Next each character of the string is written + * using the UTF-8 encoding for the character. + * + * @param s the string to be written. + * @exception UTFDataFormatException if the string is longer than + * 65,535 characters. + * @exception IOException if the underlying stream throws an IOException. + */ + public void writeUTF(String s) throws IOException { + + int numchars = s.length(); + int numbytes = 0; + + for (int i = 0 ; i < numchars ; i++) { + int c = s.charAt(i); + if ((c >= 0x0001) && (c <= 0x007F)) numbytes++; + else if (c > 0x07FF) numbytes += 3; + else numbytes += 2; + } + + if (numbytes > 65535) throw new UTFDataFormatException(); + + out.write((numbytes >>> 8) & 0xFF); + out.write(numbytes & 0xFF); + for (int i = 0 ; i < numchars ; i++) { + int c = s.charAt(i); + if ((c >= 0x0001) && (c <= 0x007F)) { + out.write(c); + } + else if (c > 0x07FF) { + out.write(0xE0 | ((c >> 12) & 0x0F)); + out.write(0x80 | ((c >> 6) & 0x3F)); + out.write(0x80 | (c & 0x3F)); + written += 2; + } + else { + out.write(0xC0 | ((c >> 6) & 0x1F)); + out.write(0x80 | (c & 0x3F)); + written += 1; + } + } + + written += numchars + 2; + + } + + /** + * Returns the number of bytes written to this little endian output stream. + * (This class is not thread-safe with respect to this method. It is + * possible that this number is temporarily less than the actual + * number of bytes written.) + * @return the value of the written field. + * @see java.io.LittleEndianOutputStream#written + */ + public int size() { + return this.written; + } + +} \ No newline at end of file diff --git a/java_console/inifile/src/main/java/com/rusefi/config/Field.java b/java_console/inifile/src/main/java/com/rusefi/config/Field.java index 463836bee5..042e996983 100644 --- a/java_console/inifile/src/main/java/com/rusefi/config/Field.java +++ b/java_console/inifile/src/main/java/com/rusefi/config/Field.java @@ -1,9 +1,13 @@ package com.rusefi.config; +import com.macfaq.io.LittleEndianOutputStream; import com.opensr5.ConfigurationImage; import org.jetbrains.annotations.NotNull; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.Objects; import static com.rusefi.config.FieldType.*; @@ -154,6 +158,29 @@ public class Field { return options[ordinal]; } + public void setValue(byte[] content, boolean value) { + ByteBuffer wrapped = ByteBuffer.wrap(content, 0, content.length); + wrapped.order(ByteOrder.LITTLE_ENDIAN); + if (bitOffset != NO_BIT_OFFSET) { + int packed = wrapped.getInt(); + int thisBit = (value ? 1 : 0) << bitOffset; + int mask = 1 << bitOffset; + int newValue = (packed & ~mask) | thisBit; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + LittleEndianOutputStream dout = new LittleEndianOutputStream(baos); + // wow worst way to modify an integer in byte array? :) + try { + dout.writeInt(newValue); +// dout.flush(); + byte[] src = baos.toByteArray(); + System.arraycopy(src, 0, content, getOffset(), 4); + baos.close(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + /** * each usage is a potential bug?! we are supposed to have explicit multiplier for each field */ @@ -196,8 +223,7 @@ public class Field { } public static Field create(String name, int offset, FieldType type, int bitOffset) { - Field field = new Field(name, offset, type, bitOffset); - return field; + return new Field(name, offset, type, bitOffset); } public static Field create(String name, int offset, FieldType type, String... options) { @@ -210,8 +236,7 @@ public class Field { } public static Field create(String name, int offset, FieldType type) { - Field field = new Field(name, offset, type); - return field; + return new Field(name, offset, type); } public String getStringValue(ConfigurationImage image) { @@ -223,4 +248,8 @@ public class Field { bb.get(bytes); return new String(bytes).trim(); } + + public boolean getBooleanValue(ConfigurationImage ci) { + return getValue(ci) != 0.0; + } } \ No newline at end of file diff --git a/java_console/models/src/test/java/com/rusefi/config/test/FieldTest.java b/java_console/models/src/test/java/com/rusefi/config/test/FieldTest.java index 70d5952834..2c18d7035b 100644 --- a/java_console/models/src/test/java/com/rusefi/config/test/FieldTest.java +++ b/java_console/models/src/test/java/com/rusefi/config/test/FieldTest.java @@ -1,13 +1,13 @@ package com.rusefi.config.test; +import com.opensr5.ConfigurationImage; import com.rusefi.config.Field; import com.rusefi.config.FieldCommandResponse; +import com.rusefi.config.generated.Fields; import com.rusefi.core.Pair; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.*; public class FieldTest { @Test @@ -30,17 +30,39 @@ public class FieldTest { } @Test - public void testPrecisionDependingOnScale() { - assertEquals("0.12302", Field.niceToString(0.12302, 4)); - assertEquals("0.1232", Field.niceToString(0.12317, 3)); + public void setBooleanValue() { + byte[] config = new byte[Fields.persistent_config_s_size]; + ConfigurationImage ci = new ConfigurationImage(config); - assertEquals("1234567.1", Field.niceToString(1234567.123, 4)); - assertEquals("10000.0", Field.niceToString(10000.00002, 4)); - assertEquals("0.002", Field.niceToString(0.002, 4)); - assertEquals("12.302", Field.niceToString(12.302, 4)); - assertEquals("12.302", Field.niceToString(12.302, 3)); - assertEquals("12.31", Field.niceToString(12.312, 2)); - assertEquals("123.02", Field.niceToString(123.02, 4)); + assertFalse(Fields.ISFORCEDINDUCTION.getBooleanValue(ci)); + assertFalse(Fields.OVERRIDETRIGGERGAPS.getBooleanValue(ci)); + assertFalse(Fields.ENABLEFAN1WITHAC.getBooleanValue(ci)); + + Fields.OVERRIDETRIGGERGAPS.setValue(config, true); + + assertFalse(Fields.ISFORCEDINDUCTION.getBooleanValue(ci)); + assertTrue(Fields.OVERRIDETRIGGERGAPS.getBooleanValue(ci)); + assertFalse(Fields.ENABLEFAN1WITHAC.getBooleanValue(ci)); + + Fields.OVERRIDETRIGGERGAPS.setValue(config, false); + + assertFalse(Fields.ISFORCEDINDUCTION.getBooleanValue(ci)); + assertFalse(Fields.OVERRIDETRIGGERGAPS.getBooleanValue(ci)); + assertFalse(Fields.ENABLEFAN1WITHAC.getBooleanValue(ci)); + } + + @Test + public void testPrecisionDependingOnScale() { + assertEquals("0.12302", Field.niceToString(0.12302, 4)); + assertEquals("0.1232", Field.niceToString(0.12317, 3)); + + assertEquals("1234567.1", Field.niceToString(1234567.123, 4)); + assertEquals("10000.0", Field.niceToString(10000.00002, 4)); + assertEquals("0.002", Field.niceToString(0.002, 4)); + assertEquals("12.302", Field.niceToString(12.302, 4)); + assertEquals("12.302", Field.niceToString(12.302, 3)); + assertEquals("12.31", Field.niceToString(12.312, 2)); + assertEquals("123.02", Field.niceToString(123.02, 4)); } }