[modbus] Modbus register array backed by bytes and other simplifications (#8865)

Signed-off-by: Sami Salonen <ssalonen@gmail.com>
This commit is contained in:
Sami Salonen
2020-11-26 19:07:49 +02:00
committed by GitHub
parent ff038bc9bb
commit b806ed45d0
32 changed files with 2140 additions and 655 deletions

View File

@@ -54,7 +54,6 @@ import org.openhab.io.transport.modbus.ModbusBitUtilities;
import org.openhab.io.transport.modbus.ModbusCommunicationInterface;
import org.openhab.io.transport.modbus.ModbusReadFunctionCode;
import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint;
import org.openhab.io.transport.modbus.ModbusRegister;
import org.openhab.io.transport.modbus.ModbusRegisterArray;
import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint;
import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint;
@@ -429,9 +428,8 @@ public class HeliosEasyControlsHandler extends BaseThingHandler {
lock.acquire();
comms.submitOneTimeWrite(
new ModbusWriteRegisterRequestBlueprint(HeliosEasyControlsBindingConstants.UNIT_ID,
HeliosEasyControlsBindingConstants.START_ADDRESS,
new ModbusRegisterArray(preparePayload(payload)), true,
HeliosEasyControlsBindingConstants.MAX_TRIES),
HeliosEasyControlsBindingConstants.START_ADDRESS, preparePayload(payload),
true, HeliosEasyControlsBindingConstants.MAX_TRIES),
result -> {
lock.release();
updateStatus(ThingStatus.ONLINE);
@@ -477,8 +475,7 @@ public class HeliosEasyControlsHandler extends BaseThingHandler {
String payload = v.getVariableString();
comms.submitOneTimeWrite(new ModbusWriteRegisterRequestBlueprint(
HeliosEasyControlsBindingConstants.UNIT_ID, HeliosEasyControlsBindingConstants.START_ADDRESS,
new ModbusRegisterArray(preparePayload(payload)), true,
HeliosEasyControlsBindingConstants.MAX_TRIES), result -> {
preparePayload(payload), true, HeliosEasyControlsBindingConstants.MAX_TRIES), result -> {
comms.submitOneTimePoll(
new ModbusReadRequestBlueprint(HeliosEasyControlsBindingConstants.UNIT_ID,
ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS,
@@ -690,25 +687,21 @@ public class HeliosEasyControlsHandler extends BaseThingHandler {
* @param payload The String representation of the payload
* @return The Register representation of the payload
*/
private ModbusRegister[] preparePayload(String payload) {
private static ModbusRegisterArray preparePayload(String payload) {
// determine number of registers
int l = (payload.length() + 1) / 2; // +1 because we need to include at least one termination symbol 0x00
if ((payload.length() + 1) % 2 != 0) {
l++;
}
byte[] asciiBytes = payload.getBytes(StandardCharsets.US_ASCII);
int bufferLength = asciiBytes.length // ascii characters
+ 1 // NUL byte
+ ((asciiBytes.length % 2 == 0) ? 1 : 0); // to have even number of bytes
assert bufferLength % 2 == 0; // Invariant, ensured above
ModbusRegister reg[] = new ModbusRegister[l];
byte[] b = payload.getBytes();
int ch = 0;
for (int i = 0; i < reg.length; i++) {
byte b1 = ch < b.length ? b[ch] : (byte) 0x00; // terminate with 0x00 if at the end of the payload
ch++;
byte b2 = ch < b.length ? b[ch] : (byte) 0x00;
ch++;
reg[i] = new ModbusRegister(b1, b2);
byte[] buffer = new byte[bufferLength];
System.arraycopy(asciiBytes, 0, buffer, 0, asciiBytes.length);
// Fill in rest of bytes with NUL bytes
for (int i = asciiBytes.length; i < buffer.length; i++) {
buffer[i] = '\0';
}
return reg;
return new ModbusRegisterArray(buffer);
}
/**
@@ -718,8 +711,8 @@ public class HeliosEasyControlsHandler extends BaseThingHandler {
* @return The value or <tt>null</tt> if an error occurred
*/
private void processResponse(HeliosVariable v, ModbusRegisterArray registers) {
String r = ModbusBitUtilities
.extractStringFromRegisters(registers, 0, registers.size() * 2, StandardCharsets.US_ASCII).toString();
String r = ModbusBitUtilities.extractStringFromRegisters(registers, 0, registers.size() * 2,
StandardCharsets.US_ASCII);
String[] parts = r.split("=", 2); // remove the part "vXXXX=" from the string
// making sure we have a proper response and the response matches the requested variable
if ((parts.length == 2) && (v.getVariableString().equals(parts[0]))) {

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.modbus.helioseasycontrols.internal;
import static org.junit.jupiter.api.Assertions.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.openhab.io.transport.modbus.ModbusRegisterArray;
/**
* @author Sami Salonen - Initial contribution
*/
public class PreparePayloadTest {
private Method preparePayloadMethod;
public PreparePayloadTest() throws NoSuchMethodException, SecurityException {
preparePayloadMethod = HeliosEasyControlsHandler.class.getDeclaredMethod("preparePayload", String.class);
preparePayloadMethod.setAccessible(true);
}
private ModbusRegisterArray preparePayload(String payload) {
try {
return (ModbusRegisterArray) preparePayloadMethod.invoke(null, payload);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
fail("Reflection failure:" + e.getMessage());
throw new RuntimeException(); // to make compiler happy
}
}
public static Collection<Object[]> data() {
return Collections.unmodifiableList(Stream
// Due to nul byte, full register full of nul bytes added
.of(new Object[] { "v00020=a", new ModbusRegisterArray(0x7630, 0x3030, 0x3230, 0x3d61, 0x0000) },
new Object[] { "v00020=aa", new ModbusRegisterArray(0x7630, 0x3030, 0x3230, 0x3d61, 0x6100) })
.collect(Collectors.toList()));
}
@ParameterizedTest
@MethodSource("data")
public void testPreparePayload(String payload, ModbusRegisterArray expectedRegisters) {
ModbusRegisterArray actual = preparePayload(payload);
assertEquals(actual.size(), expectedRegisters.size(), String.format("payload=%s", payload));
for (int i = 0; i < expectedRegisters.size(); i++) {
int expectedRegisterDataUnsigned = expectedRegisters.getRegister(i);
int actualUnsigned = actual.getRegister(i);
assertEquals(expectedRegisterDataUnsigned, actualUnsigned,
String.format("register index i=%d, payload=%s", i, payload));
}
}
}