[modbus] Modbus register array backed by bytes and other simplifications (#8865)
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
This commit is contained in:
@@ -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]))) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user