From ac7ddc8c84d73b1e42905123892be94c937c8649 Mon Sep 17 00:00:00 2001 From: Thomas Sicking <91258335+tsicking@users.noreply.github.com> Date: Wed, 6 Sep 2023 22:56:42 +0200 Subject: [PATCH] Modbus SunSpec: split modbus tasks with more than 126 registers (#2336) This PR solves issue #2311. Similar to the Edge2Edge-component, if a modbus task is longer than the limit of j2mod (= 126), it is split. --- .../AbstractOpenemsSunSpecComponent.java | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java index ff19b82f577..d78b6dee4e7 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java @@ -1,6 +1,8 @@ package io.openems.edge.bridge.modbus.sunspec; +import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Deque; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -21,6 +23,7 @@ import io.openems.edge.bridge.modbus.api.ElementToChannelScaleFactorConverter; import io.openems.edge.bridge.modbus.api.ModbusProtocol; import io.openems.edge.bridge.modbus.api.ModbusUtils; +import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; import io.openems.edge.bridge.modbus.api.element.ModbusElement; import io.openems.edge.bridge.modbus.api.element.ModbusRegisterElement; @@ -37,6 +40,11 @@ */ public abstract class AbstractOpenemsSunSpecComponent extends AbstractOpenemsModbusComponent { + /** + * Limit of a task length in j2mod. + */ + private static final int MAXIMUM_TASK_LENGTH = 126; + private final Logger log = LoggerFactory.getLogger(AbstractOpenemsSunSpecComponent.class); // The active SunSpec-Models and their reading-priority @@ -283,13 +291,13 @@ public boolean isSunSpecInitializationCompleted() { protected void addBlock(int startAddress, SunSpecModel model, Priority priority) throws OpenemsException { this.logInfo(this.log, "Adding SunSpec-Model [" + model.getBlockId() + ":" + model.label() + "] starting at [" + startAddress + "]"); - var elements = new ModbusElement[model.points().length]; + Deque elements = new ArrayDeque<>(); startAddress += 2; for (var i = 0; i < model.points().length; i++) { var point = model.points()[i]; var element = point.get().generateModbusElement(startAddress); startAddress += element.length; - elements[i] = element; + elements.add(element); var channelId = point.getChannelId(); this.addChannel(channelId); @@ -348,8 +356,37 @@ protected void addBlock(int startAddress, SunSpecModel model, Priority priority) } } - final Task readTask = new FC3ReadRegistersTask(elements[0].startAddress, priority, elements); - this.modbusProtocol.addTask(readTask); + this.addReadTasks(elements, priority); + } + + /** + * Splits the task if it is too long and adds the read tasks. + * + * @param elements the Deque of {@link ModbusElement}s for one block. + * @param priority the reading priority + * @throws OpenemsException on error + */ + private void addReadTasks(Deque elements, Priority priority) throws OpenemsException { + var length = 0; + var taskElements = new ArrayDeque(); + var element = elements.pollFirst(); + while (element != null) { + if (length + element.length > MAXIMUM_TASK_LENGTH) { + this.modbusProtocol.addTask(// + new FC3ReadRegistersTask(// + taskElements.peekFirst().startAddress, priority, // + taskElements.toArray(new AbstractModbusElement[taskElements.size()]))); + length = 0; + taskElements.clear(); + } + taskElements.add(element); + length += element.length; + element = elements.pollFirst(); + } + this.modbusProtocol.addTask(// + new FC3ReadRegistersTask(// + taskElements.peekFirst().startAddress, priority, // + taskElements.toArray(new AbstractModbusElement[taskElements.size()]))); } /**