Skip to content

Commit

Permalink
added support for variable RS485/UART serial frame lengths
Browse files Browse the repository at this point in the history
  • Loading branch information
ai-republic committed Feb 9, 2024
1 parent e4d50dc commit 9c43eba
Show file tree
Hide file tree
Showing 28 changed files with 849 additions and 372 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ protected List<ByteBuffer> sendMessage(final Port port, final int bmsNo, final D
skip--;

for (int i = 0; i < frameCount; i++) {
final ByteBuffer receiveFrame = port.receiveFrame(t -> true);
final ByteBuffer receiveFrame = port.receiveFrame();

LOG.debug("RECEIVED: {}", Port.printBuffer(receiveFrame));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.airepublic.bmstoinverter.core.BMSConfig;
import com.airepublic.bmstoinverter.core.BMSDescriptor;
import com.airepublic.bmstoinverter.core.Port;
import com.airepublic.bmstoinverter.protocol.rs485.FrameDefinition;
import com.airepublic.bmstoinverter.protocol.rs485.JSerialCommPort;
import com.fazecast.jSerialComm.SerialPort;

Expand All @@ -25,7 +26,7 @@ public Class<? extends BMS> getBMSClass() {

@Override
public Port createPort(final BMSConfig config) {
final Port port = new JSerialCommPort(config.getPortLocator(), 9600, 8, 1, SerialPort.NO_PARITY, 165, 13);
final Port port = new JSerialCommPort(config.getPortLocator(), 9600, 8, 1, SerialPort.NO_PARITY, new byte[] { (byte) 165 }, FrameDefinition.create("SACLDV"));
return port;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,27 @@
import com.airepublic.bmstoinverter.core.NoDataAvailableException;
import com.airepublic.bmstoinverter.core.Port;
import com.airepublic.bmstoinverter.core.TooManyInvalidFramesException;
import com.airepublic.bmstoinverter.core.protocol.rs485.RS485Port;

/**
* The class to handle RS485 messages from a Daly BMS.
*/
public class DalyBmsRS485Processor extends AbstractDalyBmsProcessor {
private final static Logger LOG = LoggerFactory.getLogger(AbstractDalyBmsProcessor.class);
private final ByteBuffer sendFrame = ByteBuffer.allocate(13);
private final Predicate<byte[]> validator = bytes -> {
private final Predicate<ByteBuffer> validator = buffer -> {
// check if null
if (buffer == null) {
return false;
}

// calculate checksum
int checksum = 0;
for (int i = 0; i < bytes.length - 1; i++) {
checksum += (byte) Byte.toUnsignedInt(bytes[i]);
for (int i = 0; i < buffer.capacity() - 1; i++) {
checksum += (byte) Byte.toUnsignedInt(buffer.get(i));
}

return bytes[12] == (byte) checksum;
// compare the checksum
return buffer.get(12) == (byte) checksum;
};

@Override
Expand All @@ -51,63 +57,69 @@ protected List<ByteBuffer> sendMessage(final Port port, final int bmsNo, final D
LOG.debug("SEND: {}", Port.printBuffer(sendBuffer));

try {
Thread.sleep(50);
Thread.sleep(92);
} catch (final InterruptedException e) {
}

// read the expected response frame(s)
for (int i = 0; i < frameCount; i++) {
final ByteBuffer receiveBuffer = port.receiveFrame(validator);

// check if a valid frame was received or no bytes
if (receiveBuffer == null || receiveBuffer.capacity() < ((RS485Port) port).getFrameLength()) {

// did we receive an invalid frame length
if (receiveBuffer != null && receiveBuffer.capacity() < ((RS485Port) port).getFrameLength()) {
// keep track of how often invalid frames were received
failureCount++;
LOG.debug("Wrong number of bytes received! {}", Port.printBuffer(receiveBuffer));

if (failureCount >= 10) {
throw new TooManyInvalidFramesException();
}
} else { // we received no bytes at all
// keep track of how often no bytes could be read
noDataReceived++;
LOG.warn("No bytes received: " + noDataReceived + " times!");

// if we received no bytes more than 10 times we stop and notify the handler
// to re-open the port
if (noDataReceived >= 10) {
throw new NoDataAvailableException();
}
boolean valid = false;
final ByteBuffer receiveBuffer = port.receiveFrame();

// try and wait for the next message to arrive
try {
LOG.debug("Waiting for messages to arrive....");
Thread.sleep(getDelayAfterNoBytes());
} catch (final InterruptedException e) {
}
}
valid = validator.test(receiveBuffer);

// try to receive the response again
i--;
} else {
if (valid) {
LOG.debug("RECEIVED: {}", Port.printBuffer(receiveBuffer));

// check if its the correct requested response
if (receiveBuffer.get(1) == (byte) (address - 0x40 + 1) && receiveBuffer.get(2) == (byte) cmd.id) {
framesToBeReceived--;
readBuffers.add(receiveBuffer);

final DalyMessage dalyMsg = convertReceiveFrameToDalyMessage(receiveBuffer);

if (dalyMsg != null) {
getMessageHandler().handleMessage(this, dalyMsg);
} else {
LOG.warn("Message could not be interpreted " + Port.printBuffer(receiveBuffer));
valid = false;
}
} else { // we received something but not the requested frame
valid = false;
}
} else if (receiveBuffer == null) { // received nothing
// keep track of how often no bytes could be read
noDataReceived++;
LOG.debug("No bytes received: " + noDataReceived + " times!");

// if we received no bytes more than 10 times we stop and notify the handler
// to re-open the port
if (noDataReceived >= 10) {
throw new NoDataAvailableException();
}

final DalyMessage dalyMsg = convertReceiveFrameToDalyMessage(receiveBuffer);
// try and wait for the next message to arrive
try {
LOG.debug("Waiting for messages to arrive....");
Thread.sleep(getDelayAfterNoBytes());
} catch (final InterruptedException e) {
}

if (dalyMsg != null) {
getMessageHandler().handleMessage(this, dalyMsg);
} else {
LOG.warn("Message could not be interpreted " + Port.printBuffer(receiveBuffer));
return readBuffers;
// try to receive the response again
valid = false;
}

if (!valid) { // we received an invalid frame
// keep track of how often invalid frames were received
failureCount++;
LOG.debug("Invalid frame received! {}", Port.printBuffer(receiveBuffer));

if (failureCount >= 10) {
throw new TooManyInvalidFramesException();
}

// try to receive the response again
i--;
}
}
} while (framesToBeReceived > 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class JKBmsCANProcessor extends BMS {
protected void collectData(final Port port) {
try {
final BatteryPack pack = getBatteryPack();
final ByteBuffer frame = port.receiveFrame(null);
final ByteBuffer frame = port.receiveFrame();
final int frameId = frame.getInt();
final byte[] bytes = new byte[8];
frame.get(bytes);
Expand Down
4 changes: 4 additions & 0 deletions bms-jk-rs485/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/target/
/.settings/
/.classpath
/.project
29 changes: 29 additions & 0 deletions bms-jk-rs485/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.ai-republic.bms-to-inverter</groupId>
<artifactId>bms-to-inverter-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

<artifactId>bms-jk-rs485</artifactId>

<name>${project.artifactId}-${project.version}</name>
<description>Module for the JK BMS RS485 support</description>

<properties>
<encoding>UTF-8</encoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>com.ai-republic.bms-to-inverter</groupId>
<artifactId>protocol-rs485</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.airepublic.bmstoinverter.bms.jk.rs485;

import com.airepublic.bmstoinverter.core.BMS;
import com.airepublic.bmstoinverter.core.BMSConfig;
import com.airepublic.bmstoinverter.core.BMSDescriptor;
import com.airepublic.bmstoinverter.core.Port;
import com.airepublic.bmstoinverter.protocol.rs485.FrameDefinition;
import com.airepublic.bmstoinverter.protocol.rs485.JSerialCommPort;
import com.fazecast.jSerialComm.SerialPort;

/**
* The {@link BMSDescriptor} for the Daly BMS using the CAN protocol.
*/
public class JKBmsRS485Descriptor implements BMSDescriptor {
@Override
public String getName() {
return "JK_CAN";
}


@Override
public Class<? extends BMS> getBMSClass() {
return JKBmsRS485Processor.class;
}


@Override
public Port createPort(final BMSConfig config) {
final Port port = new JSerialCommPort(config.getPortLocator(), 115000, 8, 1, SerialPort.NO_PARITY, new byte[] { 78 }, FrameDefinition.create(""));
return port;
}

}
Loading

0 comments on commit 9c43eba

Please sign in to comment.