diff --git a/README.adoc b/README.adoc index 803ac5cb..9edb591f 100644 --- a/README.adoc +++ b/README.adoc @@ -17,8 +17,8 @@ While code is divided in specific areas most ot it is present under `bundles` fo ** `org.connectorio.addons.binding` - common/shared code for binding. ** `org.connectorio.addons.binding.askoheat` - integration of Askoheat heaters (experimental). ** `org.connectorio.addons.binding.amsads` - implementation of ADS based integration for Beckhoff PLCs. - ** `org.connectorio.addons.binding.can` - generic purpose CAN binding (experimental). ** `org.connectorio.addons.binding.bacnet` - communication with BACnet enabled HVAC equipment and other commercial real estate hardware. + ** `org.connectorio.addons.binding.canbus` - generic purpose CAN bus binding (experimental). ** `org.connectorio.addons.binding.canopen` - integration of CANopen enabled deployments through SocketCAN. ** `org.connectorio.addons.binding.canopen.ta` - integration for https://ta.co.at[Technische Alternative] hardware (it is based on CANopen). ** `org.connectorio.addons.binding.plc4x` - integration with http://plc4x.apache.org[Apache PLC4X] project. diff --git a/bundles/org.connectorio.addons.binding.can/pom.xml b/bundles/org.connectorio.addons.binding.canbus/pom.xml similarity index 91% rename from bundles/org.connectorio.addons.binding.can/pom.xml rename to bundles/org.connectorio.addons.binding.canbus/pom.xml index da29c7eb..1a7a7010 100644 --- a/bundles/org.connectorio.addons.binding.can/pom.xml +++ b/bundles/org.connectorio.addons.binding.canbus/pom.xml @@ -26,13 +26,17 @@ 3.0.0-SNAPSHOT - org.connectorio.addons.binding.can + org.connectorio.addons.binding.canbus bundle - ConnectorIO - Addons - Binding - CAN + ConnectorIO - Addons - Binding - CAN bus CAN bus integration. + + org.connectorio.addons + org.connectorio.bittpl + org.connectorio.addons org.connectorio.addons.network.can diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/CANbusBindingConstants.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/CANbusBindingConstants.java new file mode 100644 index 00000000..49a1c74f --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/CANbusBindingConstants.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO sp. z o.o. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * https://www.gnu.org/licenses/gpl-3.0.txt + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package org.connectorio.addons.binding.canbus; + + +import java.util.Set; +import org.connectorio.addons.binding.BaseBindingConstants; +import org.openhab.core.thing.ThingTypeUID; + +public interface CANbusBindingConstants extends BaseBindingConstants { + + String BINDING_ID = BaseBindingConstants.identifier("canbus"); + + ThingTypeUID SOCKETCAN_BRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, "socketcan"); + ThingTypeUID MESSAGE_THING_TYPE = new ThingTypeUID(BINDING_ID, "message"); + Set SUPPORTED_THINGS = Set.of(SOCKETCAN_BRIDGE_THING_TYPE, MESSAGE_THING_TYPE); +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/CanConnection.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/CanConnection.java new file mode 100644 index 00000000..555542bc --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/CanConnection.java @@ -0,0 +1,14 @@ +package org.connectorio.addons.binding.canbus; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.function.Consumer; + +public interface CanConnection { + + CompletableFuture write(int cob, byte[] data); + + // cancellable subscription + Future subscribe(int cob, Consumer callback); + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/MessageConfiguration.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/MessageConfiguration.java new file mode 100644 index 00000000..aea321ef --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/MessageConfiguration.java @@ -0,0 +1,8 @@ +package org.connectorio.addons.binding.canbus.config; + +public class MessageConfiguration { + + int cob; + String template; + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/SocketCANConfiguration.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/SocketCANConfiguration.java new file mode 100644 index 00000000..33516f8f --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/SocketCANConfiguration.java @@ -0,0 +1,9 @@ +package org.connectorio.addons.binding.canbus.config; + +import org.connectorio.addons.binding.config.Configuration; + +public class SocketCANConfiguration implements Configuration { + + public String name; + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/BaseOffsetConfig.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/BaseOffsetConfig.java new file mode 100644 index 00000000..d321fc24 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/BaseOffsetConfig.java @@ -0,0 +1,12 @@ +package org.connectorio.addons.binding.canbus.config.channel; + +public class BaseOffsetConfig implements OffsetConfig { + + public int offset; + + @Override + public int offset() { + return offset; + } + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/ByteChannelConfig.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/ByteChannelConfig.java new file mode 100644 index 00000000..0b5d78b8 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/ByteChannelConfig.java @@ -0,0 +1,12 @@ +package org.connectorio.addons.binding.canbus.config.channel; + +public class ByteChannelConfig extends BaseOffsetConfig implements LengthConfig { + + public int length; + + @Override + public int length() { + return length; + } + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/ContactChannelConfig.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/ContactChannelConfig.java new file mode 100644 index 00000000..d4079530 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/ContactChannelConfig.java @@ -0,0 +1,8 @@ +package org.connectorio.addons.binding.canbus.config.channel; + +public class ContactChannelConfig extends BaseOffsetConfig { + + String openValue; + String closedValue; + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/LengthConfig.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/LengthConfig.java new file mode 100644 index 00000000..cf6338da --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/LengthConfig.java @@ -0,0 +1,7 @@ +package org.connectorio.addons.binding.canbus.config.channel; + +public interface LengthConfig { + + int length(); + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/NumberChannelConfig.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/NumberChannelConfig.java new file mode 100644 index 00000000..ee0a43f0 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/NumberChannelConfig.java @@ -0,0 +1,16 @@ +package org.connectorio.addons.binding.canbus.config.channel; + +import org.apache.plc4x.java.genericcan.readwrite.GenericCANDataType; + +public class NumberChannelConfig extends BaseOffsetConfig implements LengthConfig { + + public int length; + + public GenericCANDataType type; + + @Override + public int length() { + return length; + } + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/OffsetConfig.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/OffsetConfig.java new file mode 100644 index 00000000..9b8e98be --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/OffsetConfig.java @@ -0,0 +1,7 @@ +package org.connectorio.addons.binding.canbus.config.channel; + +public interface OffsetConfig { + + int offset(); + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/SwitchChannelConfig.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/SwitchChannelConfig.java new file mode 100644 index 00000000..f9b0b51e --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/config/channel/SwitchChannelConfig.java @@ -0,0 +1,8 @@ +package org.connectorio.addons.binding.canbus.config.channel; + +public class SwitchChannelConfig extends BaseOffsetConfig { + + String onValue; + String offValue; + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/discovery/CANDiscoveryParticipant.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/discovery/CANDiscoveryParticipant.java new file mode 100644 index 00000000..11d2e4dd --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/discovery/CANDiscoveryParticipant.java @@ -0,0 +1,6 @@ +package org.connectorio.addons.binding.canbus.discovery; + +// TBD +public interface CANDiscoveryParticipant { + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/DefaultCanConnection.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/DefaultCanConnection.java new file mode 100644 index 00000000..caae01ec --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/DefaultCanConnection.java @@ -0,0 +1,87 @@ +package org.connectorio.addons.binding.canbus.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import org.apache.plc4x.java.api.PlcConnection; +import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; +import org.apache.plc4x.java.api.model.PlcConsumerRegistration; +import org.apache.plc4x.java.api.value.PlcValue; +import org.apache.plc4x.java.can.generic.tag.GenericCANTag; +import org.apache.plc4x.java.genericcan.readwrite.GenericCANDataType; +import org.apache.plc4x.java.spi.values.PlcUSINT; +import org.apache.plc4x.java.spi.values.PlcValues; +import org.connectorio.addons.binding.canbus.CanConnection; + +public class DefaultCanConnection implements CanConnection { + + private final PlcConnection connection; + + public DefaultCanConnection(PlcConnection connection) { + this.connection = connection; + } + + @Override + public CompletableFuture write(int cob, byte[] data) { + GenericCANTag tag = new GenericCANTag(cob, GenericCANDataType.UNSIGNED8, 8); + return connection.writeRequestBuilder() + .addTag("data", tag, encode(data)) + .build().execute() + .thenApply(r -> null); + } + + private PlcValue encode(byte[] data) { + List values = new ArrayList<>(); + for (byte b : data) { + values.add(new PlcUSINT(b)); + } + + return PlcValues.of(values); + } + + @Override + public Future subscribe(int cob, Consumer callback) { + GenericCANTag tag = new GenericCANTag(cob, GenericCANDataType.UNSIGNED8, 8); + + final AtomicReference registration = new AtomicReference<>(); + CompletableFuture ret = new CompletableFuture<>() { + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + PlcConsumerRegistration reg = registration.get(); + if (reg != null) { + reg.unregister(); + } + return super.cancel(mayInterruptIfRunning); + } + }; + + connection.subscriptionRequestBuilder() + .addEventTag("data", tag) + .build().execute().thenApply(r -> { + PlcConsumerRegistration reg = r.getSubscriptionHandle("data") + .register(new Consumer() { + @Override + public void accept(PlcSubscriptionEvent plcSubscriptionEvent) { + Collection data = plcSubscriptionEvent.getAllShorts("data"); + callback.accept(decode(new ArrayList<>(data))); + } + }); + registration.set(reg); + return registration; + }); + + return ret; + } + + private byte[] decode(List data) { + byte[] bytes = new byte[data.size()]; + for (int index = 0; index < bytes.length; index++) { + bytes[index] = data.get(index).byteValue(); + } + return bytes; + } +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/discovery/CANInterfaceDiscoveryDelegate.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/discovery/CANInterfaceDiscoveryDelegate.java new file mode 100644 index 00000000..f58ae755 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/discovery/CANInterfaceDiscoveryDelegate.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.canbus.internal.discovery; + +import java.util.Collections; +import java.util.Set; +import org.connectorio.addons.binding.canbus.CANbusBindingConstants; +import org.connectorio.addons.network.Network; +import org.connectorio.addons.network.NetworkType; +import org.connectorio.addons.network.can.CanNetwork; +import org.connectorio.addons.network.can.CanNetworkInterfaceTypes; +import org.connectorio.addons.network.can.CanNetworkTypes; +import org.connectorio.addons.network.iface.NetworkInterface; +import org.connectorio.addons.network.iface.NetworkInterfaceRegistry; +import org.connectorio.addons.network.iface.NetworkInterfaceStateCallback; +import org.openhab.core.config.discovery.AbstractDiscoveryService; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.config.discovery.DiscoveryService; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * Basic discovery service which rely on network API to discover CAN interface. + */ +@Component(service = {DiscoveryService.class, NetworkInterfaceStateCallback.class}) +public class CANInterfaceDiscoveryDelegate extends AbstractDiscoveryService implements DiscoveryService, + NetworkInterfaceStateCallback { + + private static final Set SUPPORTED_THING_TYPES = Collections.singleton( + CANbusBindingConstants.SOCKETCAN_BRIDGE_THING_TYPE); + private final NetworkInterfaceRegistry networkInterfaceRegistry; + + @Activate + public CANInterfaceDiscoveryDelegate(@Reference NetworkInterfaceRegistry networkInterfaceRegistry) throws IllegalArgumentException { + super(SUPPORTED_THING_TYPES, 30, true); + this.networkInterfaceRegistry = networkInterfaceRegistry; + } + + @Override + protected void startScan() { + for (NetworkInterface networkInterface : networkInterfaceRegistry.getAll()) { + if (isCompatible(networkInterface)) { + discover(networkInterface); + } + } + } + + @Override + public void networkInterfaceUp(NetworkInterface networkInterface) { + if (isCompatible(networkInterface)) { + discover(networkInterface); + } + } + + @Override + public void networkInterfaceDown(NetworkInterface networkInterface) { + for (Network network : networkInterface.getNetworks()) { + if (!(network instanceof CanNetwork)) { + continue; + } + + // remove all discovery results which point to networks we just lost + thingRemoved(createThingUID(networkInterface)); + } + } + + private void discover(NetworkInterface networkInterface) { + for (Network network : networkInterface.getNetworks()) { + if (!(network instanceof CanNetwork)) { + continue; + } + + CanNetwork canNetwork = (CanNetwork) network; + NetworkType networkType = canNetwork.getType(); + if (CanNetworkTypes.CAN_RAW.equals(networkType)) { + String name = networkInterface.getUID().getName(); + final DiscoveryResult result = DiscoveryResultBuilder + .create(createThingUID(networkInterface)) + .withLabel("CAN interface " + name) + .withProperty("name", name) + .withRepresentationProperty("name") + .build(); + + thingDiscovered(result); + } + } + } + + private static ThingUID createThingUID(NetworkInterface networkInterface) { + return new ThingUID( + CANbusBindingConstants.SOCKETCAN_BRIDGE_THING_TYPE, networkInterface.getUID().getName()); + } + + private static boolean isCompatible(NetworkInterface networkInterface) { + return CanNetworkInterfaceTypes.SOCKETCAN.equals(networkInterface.getInterfaceType()) || + CanNetworkInterfaceTypes.VCAN.equals(networkInterface.getInterfaceType()); + } + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/handler/CANMessageHandler.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/handler/CANMessageHandler.java new file mode 100644 index 00000000..ff4d2fde --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/handler/CANMessageHandler.java @@ -0,0 +1,24 @@ +package org.connectorio.addons.binding.canbus.internal.handler; + +import org.connectorio.addons.binding.handler.GenericThingHandlerBase; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; + +public class CANMessageHandler extends GenericThingHandlerBase { + + public CANMessageHandler(Thing thing) { + super(thing); + } + + @Override + public void initialize() { + + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + + } + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/handler/CANThingHandlerFactory.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/handler/CANThingHandlerFactory.java new file mode 100644 index 00000000..73ea0a32 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/handler/CANThingHandlerFactory.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.canbus.internal.handler; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import org.connectorio.addons.binding.canbus.CANbusBindingConstants; +import org.connectorio.addons.binding.canbus.discovery.CANDiscoveryParticipant; +import org.connectorio.addons.binding.handler.factory.BaseThingHandlerFactory; +import org.connectorio.plc4x.extras.osgi.PlcDriverManager; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; + +@Component(service = ThingHandlerFactory.class) +public class CANThingHandlerFactory extends BaseThingHandlerFactory implements ThingHandlerFactory { + + private final List participants = new CopyOnWriteArrayList<>(); + private final PlcDriverManager driverManager; + + @Activate + public CANThingHandlerFactory(@Reference PlcDriverManager driverManager) { + super(CANbusBindingConstants.SUPPORTED_THINGS); + this.driverManager = driverManager; + } + + @Override + protected ThingHandler createHandler(Thing thing) { + if (thing instanceof Bridge) { + if (CANbusBindingConstants.SOCKETCAN_BRIDGE_THING_TYPE.equals(thing.getThingTypeUID())) { + return new SocketCANBridgeHandler((Bridge) thing, driverManager); + } + } + + if (CANbusBindingConstants.MESSAGE_THING_TYPE.equals(thing.getThingTypeUID())) { + return new CANMessageHandler(thing); + } + + return null; + } + + @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) + public void addDiscoveryParticipant(CANDiscoveryParticipant participant) { + participants.add(participant); + } + + public void removeDiscoveryParticipant(CANDiscoveryParticipant participant) { + participants.remove(participant); + } + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/handler/SocketCANBridgeHandler.java b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/handler/SocketCANBridgeHandler.java new file mode 100644 index 00000000..5e0a3101 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/java/org/connectorio/addons/binding/canbus/internal/handler/SocketCANBridgeHandler.java @@ -0,0 +1,57 @@ +package org.connectorio.addons.binding.canbus.internal.handler; + +import java.util.concurrent.CompletableFuture; +import org.apache.plc4x.java.api.PlcConnection; +import org.apache.plc4x.java.api.PlcDriver; +import org.connectorio.addons.binding.canbus.config.SocketCANConfiguration; +import org.connectorio.addons.binding.handler.GenericBridgeHandlerBase; +import org.connectorio.plc4x.extras.osgi.PlcDriverManager; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.types.Command; + +public class SocketCANBridgeHandler extends GenericBridgeHandlerBase { + + private final CompletableFuture connection = new CompletableFuture<>(); + private final PlcDriverManager driverManager; + + public SocketCANBridgeHandler(Bridge thing, PlcDriverManager driverManager) { + super(thing); + this.driverManager = driverManager; + } + + @Override + public void initialize() { + scheduler.execute(new Runnable() { + @Override + public void run() { + SocketCANConfiguration configuration = getBridgeConfig().get(); + + try { + PlcDriver driver = driverManager.getDriver("genericcan"); + PlcConnection plcConnection = driver.getConnection("genericcan:socketcan:" + configuration.name); + if (!plcConnection.isConnected()) { + plcConnection.connect(); + } + if (plcConnection.isConnected()) { + connection.complete(plcConnection); + updateStatus(ThingStatus.ONLINE); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Could not open connection"); + } + } catch (Exception e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR, + "Could not initialize handler " + e.getMessage()); + } + } + }); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + + } + +} diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.connectorio.addons.binding.canbus/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 00000000..73a50b5f --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,27 @@ + + + + + CAN bus Binding + This binding provides interaction layer for CAN enabled devices. + Ɓukasz Dywicki + + diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/resources/OH-INF/thing/channel-types.xml b/bundles/org.connectorio.addons.binding.canbus/src/main/resources/OH-INF/thing/channel-types.xml new file mode 100644 index 00000000..8951bf3a --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/resources/OH-INF/thing/channel-types.xml @@ -0,0 +1,122 @@ + + + + + + Switch + + Switchable value which can be described using two values - on and off. + + + + Bit offset from beginning of data section (counted from 0). + + + + + Value which indicates 'ON' state, described using bit template. + + + + + Value which indicates 'OFF' state, described using bit template. + + + + + + Contact + + Contact which can be described using two values - open and closed. + + + + Bit offset from beginning of data section (counted from 0). + + + + Value which indicates 'OPEN' state, described using bit template. + + + + Value which indicates 'CLOSED' state, described using bit template. + + + + + + Number + + Numeric value interpreted according to typical binary encoding scheme. + + + + Bit offset from beginning of data section (counted from 0). + + + + Number of bits which should be read or written into message. + + + + Encoding of data and its endianness. + + + + + + + + + + + + + + + + + Switch little endian encoding for written/received values. + By default, all mappings are expected to be big endian. + + false + + + + + + Image + + Raw sequence of data, with no processing values are communicated using RawType (byte sequence). + + + + Bit offset from beginning of data section (counted from 0). + + + + Number of bits which should be read or written into message. + + + + + diff --git a/bundles/org.connectorio.addons.binding.canbus/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.connectorio.addons.binding.canbus/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 00000000..fc730e59 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.canbus/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,66 @@ + + + + + + + Defines CAN interface which uses SocketCAN under the hood. + + + + + Name of interface assigned by operating system. + + + + + Time between poll cycles. + 1000 + ms + + + + + + + + + + + Mapping of a single CAN object identifier + + + + + Identifier of a message used to exchange information. + + + + + Acceptance filter for incoming message and/or patter for published message. + Please refer bit template documentation for detailed information. + + + + + + diff --git a/bundles/org.connectorio.bittpl/README.adoc b/bundles/org.connectorio.bittpl/README.adoc new file mode 100644 index 00000000..346fcb23 --- /dev/null +++ b/bundles/org.connectorio.bittpl/README.adoc @@ -0,0 +1,79 @@ += Bit Template + +The Bit Template is a basic binary format specifier which rely on combination of hex and binary notation. +Its main purpose is definition of patterns which match byte payload. + +== Template format +Templates can be constructed from four elements described in table below. + +[cols="1,2,1,1"] +|=== +|Name | Pattern| Size (bit count)| Notes + +| Nibble +| `'0' .. '9' \| 'a' .. 'f' \| 'A' .. 'F'` +| 4 +| + +| Nibble variable +| `*` +| 4 +| Written as `0000b` + +| Bit +| `'0' .. '9' \| 'a' .. 'f' \| 'A' .. 'F'` +| 1 +| + +| Bit variable +| `.` +| 1 +| Written as `0b`. + +|=== + +When template is turned again into message its variable part always default to `0b`. +It is duty of caller to fill placeholders with proper values. +What is notable - writing does not have to follow variable parts. + +=== Example templates + +Below table list example templates and messages with their match status. + +[cols="1,1,2"] +|=== +|Template | Message | Matching / Notes + +| xAA xAB xAC +| AA AB AC 00 +| Yes / remaining part of message is not interpreted + +| xAA xAB xAC ** +| AA AB AC 00 +| Yes + +| xAA xAB xAC ** +| AA AB AB 00 +| No / third byte does not match `xAC` + +| xAA xAB xAC ** +| AA AB AC 01 +| Yes + +| xAA xAB xAC ** +| AA AB AC FF +| Yes + +| xAA xAB xAC b0000000. +| AA AB AC 00 +| Yes + +| xAA xAB xAC b0000000. +| AA AB AC 01 +| Yes + +| xAA xAB xAC b0000000. +| AA AB AC 02 +| No / bit representation of last byte is `00000010` + +|=== \ No newline at end of file diff --git a/bundles/org.connectorio.bittpl/pom.xml b/bundles/org.connectorio.bittpl/pom.xml new file mode 100644 index 00000000..f6f8fa6d --- /dev/null +++ b/bundles/org.connectorio.bittpl/pom.xml @@ -0,0 +1,94 @@ + + + + + 4.0.0 + + + org.connectorio.addons + bundles + 3.0.0-SNAPSHOT + + + org.connectorio.bittpl + bundle + + ConnectorIO - BitTPL + Bit Template. + + + + org.antlr + antlr4-runtime + + + com.github.jinahya + bit-io + + + + org.junit.jupiter + junit-jupiter-api + + + org.assertj + assertj-core + + + + + + + org.antlr + antlr4-maven-plugin + + + antlr + + antlr4 + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-feature-xml + none + + + add-anltr-sources + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/antlr4/ + + + + + + + + + diff --git a/bundles/org.connectorio.bittpl/src/main/antlr4/org/connectorio/bittpl/parser/BitTPL.g4 b/bundles/org.connectorio.bittpl/src/main/antlr4/org/connectorio/bittpl/parser/BitTPL.g4 new file mode 100644 index 00000000..d47a2b28 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/antlr4/org/connectorio/bittpl/parser/BitTPL.g4 @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +grammar BitTPL; + +// This grammar is a basic definition of permitted inputs for bit templates + +segments + : segment* EOF + ; + +segment + : ( binary | octet ) WS? + ; + +binary + : 'b' bit=bitSeq + ; + +octet + : 'x' hex=hexSeq + ; + + +hexSeq : HEX_SQ+; +bitSeq : BIT_SQ+; + +BIT_SQ : BIT | '.'; +BIT : '0' | '1'; + +HEX_SQ : HEX_DIGIT | '*'; + +HEX_DIGIT + : '0' .. '9' | 'a' .. 'f' | 'A' .. 'F' + ; + + +WS + : ( ' ' ) -> channel ( HIDDEN ) + ; \ No newline at end of file diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/Template.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/Template.java new file mode 100644 index 00000000..836fd2c4 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/Template.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl; + +import com.github.jinahya.bit.io.ArrayByteInput; +import com.github.jinahya.bit.io.ArrayByteOutput; +import com.github.jinahya.bit.io.BitInput; +import com.github.jinahya.bit.io.DefaultBitInput; +import com.github.jinahya.bit.io.DefaultBitOutput; +import java.io.IOException; +import java.util.List; +import org.connectorio.bittpl.segment.Element; + +public class Template { + + protected final List elements; + private final int bitLength; + + public Template(List elements) { + this.elements = elements; + int count = 0; + for (Element element : elements) { + count += element.length(); + } + this.bitLength = count; + } + + public boolean matches(byte[] seq) { + ArrayByteInput byteInput = new ArrayByteInput(seq); + BitInput input = new DefaultBitInput(byteInput); + + // iterate over elements + for (int index = 0; index < elements.size(); index++) { + Element element = elements.get(index); + try { + boolean matches = element.matches(input); + if (!matches) { + return false; + } + } catch (IOException e) { + return false; + } + } + + return true; + } + + public byte[] toMessage() throws IOException { + byte[] target = new byte[bitLength / 8]; + DefaultBitOutput output = new DefaultBitOutput(new ArrayByteOutput(target)); + for (Element element : elements) { + element.write(output); + } + return target; + } + +} diff --git a/bundles/org.connectorio.addons.binding.can/src/main/java/org/connectorio/addons/binding/can/statistic/CANStatisticCollector.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/TemplateException.java similarity index 62% rename from bundles/org.connectorio.addons.binding.can/src/main/java/org/connectorio/addons/binding/can/statistic/CANStatisticCollector.java rename to bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/TemplateException.java index 57000cd3..a99bec45 100644 --- a/bundles/org.connectorio.addons.binding.can/src/main/java/org/connectorio/addons/binding/can/statistic/CANStatisticCollector.java +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/TemplateException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 ConnectorIO Sp. z o.o. + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,18 +15,19 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.connectorio.addons.binding.can.statistic; - -import javax.measure.Quantity; +package org.connectorio.bittpl; /** - * Helper interface to gather CAN statistics. + * Error thrown in case when template parsing or processing fails. */ -@Deprecated -public interface CANStatisticCollector> { +public class TemplateException extends RuntimeException { - String getName(); + public TemplateException(String message) { + super(message); + } - Quantity getStatistic(); + public TemplateException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/TemplateParser.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/TemplateParser.java new file mode 100644 index 00000000..c026719f --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/TemplateParser.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl; + +import java.util.ArrayList; +import java.util.List; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.ConsoleErrorListener; +import org.antlr.v4.runtime.tree.ErrorNode; +import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.antlr.v4.runtime.tree.TerminalNode; +import org.connectorio.bittpl.parser.BitTPLBaseListener; +import org.connectorio.bittpl.parser.BitTPLLexer; +import org.connectorio.bittpl.parser.BitTPLParser; +import org.connectorio.bittpl.parser.BitTPLParser.BitSeqContext; +import org.connectorio.bittpl.parser.BitTPLParser.HexSeqContext; +import org.connectorio.bittpl.parser.TemplateErrorListener; +import org.connectorio.bittpl.segment.Bit; +import org.connectorio.bittpl.segment.Element; +import org.connectorio.bittpl.segment.Nibble; +import org.connectorio.bittpl.segment.BitWildcard; +import org.connectorio.bittpl.segment.NibbleWildcard; + +public class TemplateParser { + + public static Template parse(String template) { + BitTPLLexer lexer = new BitTPLLexer(CharStreams.fromString(template)); + lexer.removeErrorListener(ConsoleErrorListener.INSTANCE); + BitTPLParser parser = new BitTPLParser(new CommonTokenStream(lexer)); + parser.removeErrorListener(ConsoleErrorListener.INSTANCE); + parser.addErrorListener(new TemplateErrorListener()); + + Listener listener = new Listener(); + new ParseTreeWalker().walk(listener, parser.segments()); + + return new Template(listener.elements); + } + + static class Listener extends BitTPLBaseListener { + private final List elements = new ArrayList<>(); + + private int offset = 0; + private final static String STAR = "*"; + private final static String DOT = "."; + + @Override + public void enterHexSeq(HexSeqContext ctx) { + for (TerminalNode node : ctx.HEX_SQ()) { + String nibble = node.getText(); + if (STAR.equals(nibble)) { + elements.add(new NibbleWildcard(offset)); + } else { + elements.add(new Nibble(offset, nibble)); + } + offset += 8; + } + } + + + @Override + public void enterBitSeq(BitSeqContext ctx) { + for (TerminalNode node : ctx.BIT_SQ()) { + String bit = node.getText(); + if (DOT.equals(bit)) { + elements.add(new BitWildcard(offset)); + } else { + elements.add(new Bit(offset, bit.equals("1"))); + } + offset += 1; + } + } + + @Override + public void visitErrorNode(ErrorNode node) { + super.visitErrorNode(node); + throw new IllegalArgumentException(node.toString()); + } + } + +} diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/bitio/BasicByteInput.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/bitio/BasicByteInput.java new file mode 100644 index 00000000..395ff1a8 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/bitio/BasicByteInput.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl.bitio; + +import com.github.jinahya.bit.io.ArrayByteInput; + +/** + * Byte input which supports arbitrary navigation over underlying buffer. + */ +public class BasicByteInput extends ArrayByteInput { + + public BasicByteInput(byte[] source) { + super(source); + } + + @Override + public void setIndex(int index) { + super.setIndex(index); + } + +} diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/bitio/BasicByteOutput.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/bitio/BasicByteOutput.java new file mode 100644 index 00000000..6218d6d4 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/bitio/BasicByteOutput.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl.bitio; + +import com.github.jinahya.bit.io.ArrayByteOutput; + +/** + * Output which allows navigation over underlying buffer. + */ +public class BasicByteOutput extends ArrayByteOutput { + + public BasicByteOutput(byte[] target) { + super(target); + } + + public void setIndex(int index) { + super.setIndex(index); + } + +} diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/parser/TemplateErrorListener.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/parser/TemplateErrorListener.java new file mode 100644 index 00000000..2b384208 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/parser/TemplateErrorListener.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl.parser; + +import java.util.BitSet; +import org.antlr.v4.runtime.ANTLRErrorListener; +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; +import org.antlr.v4.runtime.atn.ATNConfigSet; +import org.antlr.v4.runtime.dfa.DFA; +import org.connectorio.bittpl.TemplateException; + +public class TemplateErrorListener implements ANTLRErrorListener { + + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, + int charPositionInLine, String msg, RecognitionException e) { + + throw new TemplateException(msg + "(at " + line + ":" + charPositionInLine + ")"); + } + + @Override + public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, + boolean exact, BitSet ambigAlts, ATNConfigSet configs) { + + } + + @Override + public void reportAttemptingFullContext(Parser recognizer, DFA dfa, int startIndex, int stopIndex, + BitSet conflictingAlts, ATNConfigSet configs) { + + } + + @Override + public void reportContextSensitivity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, + int prediction, ATNConfigSet configs) { + + } +} diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/Bit.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/Bit.java new file mode 100644 index 00000000..ab1fd1b8 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/Bit.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl.segment; + +import com.github.jinahya.bit.io.BitInput; +import com.github.jinahya.bit.io.BitOutput; +import java.io.IOException; + +public class Bit extends ElementBase { + + private final boolean value; + + public Bit(int offset, boolean value) { + super(offset, 1); + this.value = value; + } + + @Override + public boolean matches(BitInput input) throws IOException { + boolean bit = input.readBoolean(); + return value == bit; + } + + @Override + public void write(BitOutput output) throws IOException { + output.writeBoolean(value); + } + +} diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/BitWildcard.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/BitWildcard.java new file mode 100644 index 00000000..d4513abc --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/BitWildcard.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl.segment; + +import com.github.jinahya.bit.io.BitInput; +import com.github.jinahya.bit.io.BitOutput; +import java.io.IOException; + +public class BitWildcard extends ElementBase { + + public BitWildcard(int offset) { + super(offset, 1); + } + + @Override + public boolean matches(BitInput input) throws IOException { + input.readBoolean(); + return true; + } + + @Override + public void write(BitOutput output) throws IOException { + output.writeBoolean(false); + } + +} diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/Element.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/Element.java new file mode 100644 index 00000000..f0340b56 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/Element.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl.segment; + +import com.github.jinahya.bit.io.BitInput; +import com.github.jinahya.bit.io.BitOutput; +import java.io.IOException; + +public interface Element { + + int offset(); + int length(); + + boolean matches(BitInput input) throws IOException; + + void write(BitOutput output) throws IOException; + +} diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/ElementBase.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/ElementBase.java new file mode 100644 index 00000000..ce2188b8 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/ElementBase.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl.segment; + +public abstract class ElementBase implements Element { + + private final int offset; + private final int length; + + public ElementBase(int offset, int length) { + this.offset = offset; + this.length = length; + } + + @Override + public int offset() { + return offset; + } + + @Override + public int length() { + return length; + } + +} diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/Nibble.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/Nibble.java new file mode 100644 index 00000000..a7d100a6 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/Nibble.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl.segment; + +import com.github.jinahya.bit.io.BitInput; +import com.github.jinahya.bit.io.BitOutput; +import java.io.IOException; + +public class Nibble extends ElementBase { + + private final byte value; + + public Nibble(int offset, String nibble) { + super(offset, 4); + this.value = Byte.parseByte(nibble, 16); + } + + @Override + public boolean matches(BitInput input) throws IOException { + int nibble = input.readByte(true, 4); + return value == nibble; + } + + @Override + public void write(BitOutput output) throws IOException { + output.writeByte(true, 4, value); + } + + @Override + public String toString() { + return "Nibble [" + offset() + "=" + this.value + "]"; + } + +} diff --git a/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/NibbleWildcard.java b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/NibbleWildcard.java new file mode 100644 index 00000000..a7beead0 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/main/java/org/connectorio/bittpl/segment/NibbleWildcard.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl.segment; + +import com.github.jinahya.bit.io.BitInput; +import com.github.jinahya.bit.io.BitOutput; +import java.io.IOException; + +public class NibbleWildcard extends ElementBase { + + public NibbleWildcard(int offset) { + super(offset, 4); + } + + @Override + public boolean matches(BitInput input) throws IOException { + input.readByte8(); + return true; + } + + @Override + public void write(BitOutput output) throws IOException { + output.writeByte(true, 4, (byte) 0x00); + } + +} diff --git a/bundles/org.connectorio.bittpl/src/test/java/org/connectorio/bittpl/TemplateParserTest.java b/bundles/org.connectorio.bittpl/src/test/java/org/connectorio/bittpl/TemplateParserTest.java new file mode 100644 index 00000000..d3fb4528 --- /dev/null +++ b/bundles/org.connectorio.bittpl/src/test/java/org/connectorio/bittpl/TemplateParserTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023-2023 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.bittpl; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.IOException; +import org.junit.jupiter.api.Test; + +class TemplateParserTest { + + @Test + void testParser() throws Exception { + Template template = TemplateParser.parse("xAA xAB xAC b.... ...1"); + + byte[] message = new byte[] {(byte) 0xAA, (byte) 0xAB, (byte) 0xAC, 0x01}; + boolean matches = template.matches(message); + assertThat(matches).isTrue(); + + byte[] output = template.toMessage(); + assertThat(output).isEqualTo(message); + + message = new byte[] {(byte) 0xAA, (byte) 0xAB, (byte) 0xAC, 0x00}; + matches = template.matches(message); + assertThat(matches).isFalse(); + + message = new byte[] {(byte) 0xAA, (byte) 0xAB, (byte) 0xAC, 0x01, 0x00}; + matches = template.matches(message); + assertThat(matches).isTrue(); + } + + @Test + void testEmptyInput() throws IOException { + Template template = TemplateParser.parse(""); + assertThat(template.matches(new byte[0])) + .isTrue(); + + assertThat(template.toMessage()) + .isEqualTo(new byte[0]); + } + + @Test + void testInvalidHexInput() { + assertThatThrownBy(() -> TemplateParser.parse("a")) + .isInstanceOf(TemplateException.class) + .hasMessageContaining("at 1:0"); + } + +} \ No newline at end of file diff --git a/bundles/pom.xml b/bundles/pom.xml index 38e38753..582672bb 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -39,7 +39,7 @@ org.connectorio.addons.binding.amsads org.connectorio.addons.binding.askoheat org.connectorio.addons.binding.bacnet - org.connectorio.addons.binding.can + org.connectorio.addons.binding.canbus org.connectorio.addons.binding.canopen org.connectorio.addons.binding.canopen.ta org.connectorio.addons.binding.fatek @@ -97,6 +97,7 @@ org.connectorio.addons.test org.connectorio.addons.transformation.inverse org.connectorio.addons.ui.iconify + org.connectorio.bittpl org.connectorio.chrono org.connectorio.logtail org.connectorio.logtail.web diff --git a/features/org.connectorio.addons.feature.can/pom.xml b/features/org.connectorio.addons.feature.canbus/pom.xml similarity index 86% rename from features/org.connectorio.addons.feature.can/pom.xml rename to features/org.connectorio.addons.feature.canbus/pom.xml index f0e7f37e..44cc6620 100644 --- a/features/org.connectorio.addons.feature.can/pom.xml +++ b/features/org.connectorio.addons.feature.canbus/pom.xml @@ -26,16 +26,16 @@ 3.0.0-SNAPSHOT - org.connectorio.addons.feature.can + org.connectorio.addons.feature.canbus pom - ConnectorIO - Addons - Features - CAN - CAN deployment archive. + ConnectorIO - Addons - Features - CAN bus + CAN bus deployment archive. org.connectorio.addons - org.connectorio.addons.binding.can + org.connectorio.addons.binding.canbus @@ -56,6 +56,12 @@ features xml + + org.connectorio.addons + org.connectorio.feature.bittpl + features + xml + @@ -101,6 +107,7 @@ mvn:org.connectorio.plc4x.extras.features/org.connectorio.plc4x.extras.feature.osgi/${plc4x-extras.version}/xml/features mvn:org.connectorio.plc4x.extras.features/org.connectorio.plc4x.extras.feature.decorator/${plc4x-extras.version}/xml/features mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${openhab.version}/xml/features + mvn:org.connectorio.addons/org.connectorio.feature.bittpl/${project.version}/xml/features co7io-binding-* diff --git a/features/org.connectorio.addons.feature.can/src/main/feature/feature.xml b/features/org.connectorio.addons.feature.canbus/src/main/feature/feature.xml similarity index 72% rename from features/org.connectorio.addons.feature.can/src/main/feature/feature.xml rename to features/org.connectorio.addons.feature.canbus/src/main/feature/feature.xml index 48a2dc13..0249e792 100644 --- a/features/org.connectorio.addons.feature.can/src/main/feature/feature.xml +++ b/features/org.connectorio.addons.feature.canbus/src/main/feature/feature.xml @@ -1,6 +1,6 @@ - + mvn:org.connectorio.addons/org.connectorio.addons.feature.plc4x/${project.version}/xml/features mvn:org.connectorio.addons/org.connectorio.addons.feature.network/${project.version}/xml/features - - co7io-binding-can + + co7io-binding-canbus - + openhab-runtime-base co7io-network-can + co7io-bittpl plc4j-can-driver co7io-binding-plc4x co7io-plc4j-decorator-phase co7io-plc4j-decorator-retry co7io-plc4j-decorator-throttle - mvn:org.connectorio.addons/org.connectorio.addons.binding.can/${project.version} + mvn:org.connectorio.addons/org.connectorio.addons.binding.canbus/${project.version} diff --git a/features/org.connectorio.feature.bittpl/pom.xml b/features/org.connectorio.feature.bittpl/pom.xml new file mode 100644 index 00000000..e1423c3b --- /dev/null +++ b/features/org.connectorio.feature.bittpl/pom.xml @@ -0,0 +1,99 @@ + + + + + 4.0.0 + + + org.connectorio.addons + features + 3.0.0-SNAPSHOT + + + org.connectorio.feature.bittpl + pom + + ConnectorIO - Features - BitTpl + Bit template feature. + + + + org.connectorio.addons + org.connectorio.bittpl + + + + + org.apache.karaf.features + framework + kar + provided + + + + + + + ${basedir}/src/main/feature + true + ${project.build.directory}/feature + + + + + org.apache.maven.plugins + maven-resources-plugin + + + + resources + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + org.apache.karaf.tooling + karaf-maven-plugin + + + karaf-verification + + + co7io-* + + + + + aggregate-descriptor + none + + + oh-kar + none + + + + + + + diff --git a/features/org.connectorio.feature.bittpl/src/main/feature/feature.xml b/features/org.connectorio.feature.bittpl/src/main/feature/feature.xml new file mode 100644 index 00000000..ba8c7bb9 --- /dev/null +++ b/features/org.connectorio.feature.bittpl/src/main/feature/feature.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/features/pom.xml b/features/pom.xml index 2ed426e7..9fcba873 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -38,7 +38,7 @@ org.connectorio.addons.feature.amsads org.connectorio.addons.feature.askoheat org.connectorio.addons.feature.bacnet - org.connectorio.addons.feature.can + org.connectorio.addons.feature.canbus org.connectorio.addons.feature.canopen org.connectorio.addons.feature.fatek org.connectorio.addons.feature.io @@ -57,6 +57,7 @@ org.connectorio.addons.feature.s7 org.connectorio.addons.feature.smartme org.connectorio.addons.feature.wmbus + org.connectorio.feature.bittpl org.connectorio.feature.chrono diff --git a/itests/org.connectorio.addons.itest.can/pom.xml b/itests/org.connectorio.addons.itest.canbus/pom.xml similarity index 86% rename from itests/org.connectorio.addons.itest.can/pom.xml rename to itests/org.connectorio.addons.itest.canbus/pom.xml index 20e438f3..44b719c3 100644 --- a/itests/org.connectorio.addons.itest.can/pom.xml +++ b/itests/org.connectorio.addons.itest.canbus/pom.xml @@ -26,15 +26,15 @@ 3.0.0-SNAPSHOT - org.connectorio.addons.itest.can + org.connectorio.addons.itest.canbus - ConnectorIO - Addons - ITests - CAN + ConnectorIO - Addons - ITests - CAN bus Integration tests of CAN. org.connectorio.addons - org.connectorio.addons.kar.can + org.connectorio.addons.kar.canbus kar @@ -50,7 +50,7 @@ org.apache.maven.plugins maven-dependency-plugin - org.connectorio.addons.kar.can + org.connectorio.addons.kar.canbus diff --git a/itests/org.connectorio.addons.itest.can/src/test/java/org/connectorio/addons/itest/can/CANOfflineKarInstallationTest.java b/itests/org.connectorio.addons.itest.canbus/src/test/java/org/connectorio/addons/itest/canbus/CANbusOfflineKarInstallationTest.java similarity index 78% rename from itests/org.connectorio.addons.itest.can/src/test/java/org/connectorio/addons/itest/can/CANOfflineKarInstallationTest.java rename to itests/org.connectorio.addons.itest.canbus/src/test/java/org/connectorio/addons/itest/canbus/CANbusOfflineKarInstallationTest.java index 1dfe245f..0331b694 100644 --- a/itests/org.connectorio.addons.itest.can/src/test/java/org/connectorio/addons/itest/can/CANOfflineKarInstallationTest.java +++ b/itests/org.connectorio.addons.itest.canbus/src/test/java/org/connectorio/addons/itest/canbus/CANbusOfflineKarInstallationTest.java @@ -15,16 +15,16 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.connectorio.addons.itest.can; +package org.connectorio.addons.itest.canbus; import org.connectorio.addons.itest.OfflineKarInstallationTest; import org.testcontainers.junit.jupiter.Testcontainers; @Testcontainers -public class CANOfflineKarInstallationTest extends OfflineKarInstallationTest { +public class CANbusOfflineKarInstallationTest extends OfflineKarInstallationTest { - public CANOfflineKarInstallationTest() { - super("can", "binding", "co7io-can"); + public CANbusOfflineKarInstallationTest() { + super("canbus", "binding", "co7io-canbus"); } } diff --git a/itests/pom.xml b/itests/pom.xml index 9b0f1beb..961dda94 100644 --- a/itests/pom.xml +++ b/itests/pom.xml @@ -37,7 +37,7 @@ org.connectorio.addons.itest org.connectorio.addons.itest.amsads org.connectorio.addons.itest.bacnet - org.connectorio.addons.itest.can + org.connectorio.addons.itest.canbus org.connectorio.addons.itest.canopen org.connectorio.addons.itest.fatek org.connectorio.addons.itest.managed diff --git a/kars/org.connectorio.addons.kar.can/pom.xml b/kars/org.connectorio.addons.kar.canbus/pom.xml similarity index 83% rename from kars/org.connectorio.addons.kar.can/pom.xml rename to kars/org.connectorio.addons.kar.canbus/pom.xml index 759ececa..91feeb83 100644 --- a/kars/org.connectorio.addons.kar.can/pom.xml +++ b/kars/org.connectorio.addons.kar.canbus/pom.xml @@ -26,16 +26,16 @@ 3.0.0-SNAPSHOT - org.connectorio.addons.kar.can + org.connectorio.addons.kar.canbus kar - ConnectorIO - Addons - KARs - CAN - CAN deployment archive dedicated to openHAB runtime. + ConnectorIO - Addons - KARs - CAN bus + CAN bus deployment archive dedicated to openHAB runtime. org.connectorio.addons - org.connectorio.addons.feature.can + org.connectorio.addons.feature.canbus features xml @@ -51,6 +51,12 @@ features xml + + org.connectorio.addons + org.connectorio.feature.bittpl + features + xml + org.connectorio.addons org.connectorio.addons.feature.plc4x diff --git a/kars/pom.xml b/kars/pom.xml index f2f2fdad..e7bd0c0e 100644 --- a/kars/pom.xml +++ b/kars/pom.xml @@ -36,7 +36,7 @@ org.connectorio.addons.kar.amsads org.connectorio.addons.kar.bacnet - org.connectorio.addons.kar.can + org.connectorio.addons.kar.canbus org.connectorio.addons.kar.canopen org.connectorio.addons.kar.fatek org.connectorio.addons.kar.managed diff --git a/parent/pom.xml b/parent/pom.xml index e6679e1f..7d4d1aa3 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -68,6 +68,8 @@ 3.2.1 3.0.1 1.17.6 + 4.13.1 + 2.0.5 @@ -92,6 +94,20 @@ features xml + + + org.connectorio.addons + org.connectorio.bittpl + ${project.version} + + + org.connectorio.addons + org.connectorio.feature.bittpl + ${project.version} + features + xml + + org.connectorio.addons org.connectorio.addons.communication.watchdog @@ -279,19 +295,19 @@ org.connectorio.addons - org.connectorio.addons.binding.can + org.connectorio.addons.binding.canbus ${project.version} org.connectorio.addons - org.connectorio.addons.feature.can + org.connectorio.addons.feature.canbus ${project.version} features xml org.connectorio.addons - org.connectorio.addons.kar.can + org.connectorio.addons.kar.canbus ${project.version} kar @@ -1353,12 +1369,28 @@ commons-lang3 3.11 + + + org.antlr + antlr4-runtime + ${antlr4.version} + + + com.github.jinahya + bit-io + ${bit-io.version} + + + org.antlr + antlr4-maven-plugin + ${antlr4.version} + org.apache.felix maven-bundle-plugin