Updated zwave libs with upstream jserialcomm implementaion

This commit is contained in:
Ziver Koc 2018-02-26 21:29:40 +01:00
parent b8b0a1e62b
commit d33ebbfd25
15 changed files with 158 additions and 1397 deletions

View file

@ -1,72 +0,0 @@
/*******************************************************************************
* Copyright (c) 2013 Whizzo Software, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.whizzosoftware.wzwave.controller.netty;
import com.whizzosoftware.wzwave.channel.*;
import com.whizzosoftware.wzwave.codec.ZWaveFrameDecoder;
import com.whizzosoftware.wzwave.codec.ZWaveFrameEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.jsc.JSerialCommChannel;
import io.netty.channel.oio.OioEventLoopGroup;
import java.net.SocketAddress;
/**
* A abstract initializer
*
* @author Ziver Koc
*/
abstract class AbstractNettyChannelInitializer<T extends Channel> extends ChannelInitializer<T> {
protected String serialPort;
private ZWaveChannelInboundHandler inboundHandler;
protected Bootstrap bootstrap;
protected Channel channel;
public AbstractNettyChannelInitializer(String serialPort, ZWaveChannelListener listener) {
this.serialPort = serialPort;
this.inboundHandler = new ZWaveChannelInboundHandler(listener);
bootstrap = new Bootstrap();
bootstrap.group(new OioEventLoopGroup());
bootstrap.handler(this);
}
@Override
protected void initChannel(T channel) throws Exception {
this.channel = channel;
doInitChannel(channel);
// Setup general channel handlers and coders
channel.pipeline().addLast("decoder", new ZWaveFrameDecoder());
channel.pipeline().addLast("ack", new ACKInboundHandler());
channel.pipeline().addLast("encoder", new ZWaveFrameEncoder());
channel.pipeline().addLast("writeQueue", new FrameQueueHandler());
channel.pipeline().addLast("transaction", new TransactionInboundHandler());
channel.pipeline().addLast("handler", inboundHandler);
}
public Bootstrap getBootstrap() {
return bootstrap;
}
public Channel getChannel() {
return channel;
}
public abstract SocketAddress getSocketAddress();
protected abstract void doInitChannel(T channel) throws Exception;
}

View file

@ -1,44 +0,0 @@
/*******************************************************************************
* Copyright (c) 2013 Whizzo Software, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.whizzosoftware.wzwave.controller.netty;
import com.whizzosoftware.wzwave.channel.ZWaveChannelListener;
import io.netty.channel.jsc.JSCChannelConfig;
import io.netty.channel.jsc.JSCDeviceAddress;
import io.netty.channel.jsc.JSerialCommChannel;
/**
* A jSerialComm serial port initializer
*
* @author Ziver Koc
*/
public class NettyJSCChannelInitializer extends AbstractNettyChannelInitializer<JSerialCommChannel> {
public NettyJSCChannelInitializer(String serialPort, ZWaveChannelListener listener) {
super(serialPort, listener);
bootstrap.channel(JSerialCommChannel.class);
}
@Override
protected void doInitChannel(JSerialCommChannel channel) throws Exception {
this.channel = channel;
channel.config().setBaudrate(115200);
channel.config().setDatabits(8);
channel.config().setParitybit(JSCChannelConfig.Paritybit.NONE);
channel.config().setStopbits(JSCChannelConfig.Stopbits.STOPBITS_1);
}
@Override
public JSCDeviceAddress getSocketAddress() {
return new JSCDeviceAddress(serialPort);
}
}

View file

@ -1,45 +0,0 @@
/*******************************************************************************
* Copyright (c) 2013 Whizzo Software, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.whizzosoftware.wzwave.controller.netty;
import com.whizzosoftware.wzwave.channel.ZWaveChannelListener;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.rxtx.RxtxChannel;
import io.netty.channel.rxtx.RxtxChannelConfig;
import io.netty.channel.rxtx.RxtxDeviceAddress;
/**
* A RxTx serial port initializer
*
* @author Ziver Koc
*/
public class NettyRxtxChannelInitializer extends AbstractNettyChannelInitializer<RxtxChannel> {
public NettyRxtxChannelInitializer(String serialPort, ZWaveChannelListener listener) {
super(serialPort, listener);
bootstrap.channel(RxtxChannel.class);
}
@Override
protected void doInitChannel(RxtxChannel channel) throws Exception {
channel.config().setBaudrate(115200);
channel.config().setDatabits(RxtxChannelConfig.Databits.DATABITS_8);
channel.config().setParitybit(RxtxChannelConfig.Paritybit.NONE);
channel.config().setStopbits(RxtxChannelConfig.Stopbits.STOPBITS_1);
}
@Override
public RxtxDeviceAddress getSocketAddress() {
return new RxtxDeviceAddress(serialPort);
}
}

View file

@ -1,467 +0,0 @@
/*
*******************************************************************************
* Copyright (c) 2013 Whizzo Software, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************
*/
package com.whizzosoftware.wzwave.controller.netty;
import com.whizzosoftware.wzwave.channel.*;
import com.whizzosoftware.wzwave.channel.event.*;
import com.whizzosoftware.wzwave.commandclass.WakeUpCommandClass;
import com.whizzosoftware.wzwave.controller.ZWaveController;
import com.whizzosoftware.wzwave.controller.ZWaveControllerContext;
import com.whizzosoftware.wzwave.controller.ZWaveControllerListener;
import com.whizzosoftware.wzwave.frame.*;
import com.whizzosoftware.wzwave.node.*;
import com.whizzosoftware.wzwave.persist.PersistentStore;
import com.whizzosoftware.wzwave.persist.mapdb.MapDbPersistentStore;
import com.whizzosoftware.wzwave.util.ByteUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.oio.OioEventLoopGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
/**
* A Netty implementation of a ZWaveController.
*
* The pipeline looks like this:
*
* I/O Request via Channel or
* ChannelHandlerContext
* |
* +----------------------------------------------------------------+-------------------+
* | ChannelPipeline | |
* | | |
* | +--------------------------------+ | |
* | | ZWaveChannelInboundHandler | | |
* | +---------------+----------------+ | |
* | /|\ | |
* | | | |
* | +---------------+----------------+ | |
* | | TransactionInboundHandler | | |
* | +---------------+----------------+ | |
* | /|\ | |
* | | \|/ |
* | +---------------+-------------------------------------------+--------------+ |
* | | FrameQueueHandler | |
* | +---------------+-------------------------------------------+--------------+ |
* | /|\ | |
* | | | |
* | +---------------+----------------+ | |
* | | ACKInboundHandler | | |
* | +---------------+----------------+ | |
* | /|\ | |
* | | | |
* | +---------------+----------------+ +-------------+--------------+ |
* | | ZWaveFrameDecoder | | ZWaveFrameEncoder | |
* | +---------------+----------------+ +-------------+--------------+ |
* | /|\ | |
* +--------------------+-------------------------------------------+-------------------+
* | | \|/ |
* +--------------------+-------------------------------------------+-------------------+
* | | | |
* | [ Socket.read() ] [ Socket.write() ] |
* +------------------------------------------------------------------------------------+
*
* @author Dan Noguerol
*/
public class NettyZWaveController implements ZWaveController, ZWaveControllerContext, ZWaveControllerListener, ZWaveChannelListener, NodeListener {
private static final Logger logger = LoggerFactory.getLogger(NettyZWaveController.class);
private String serialPort;
private PersistentStore store;
private AbstractNettyChannelInitializer serial;
private String libraryVersion;
private Integer homeId;
private Byte nodeId;
private ZWaveControllerListener listener;
private final List<ZWaveNode> nodes = new ArrayList<>();
private final Map<Byte,ZWaveNode> nodeMap = new HashMap<>();
/**
* Constructor.
*
* @param serialPort the serial port the Z-Wave controller is accessible from
* @param dataDirectory a directory in which to store persistent data
*/
public NettyZWaveController(String serialPort, File dataDirectory) {
this(serialPort, new MapDbPersistentStore(dataDirectory));
}
/**
* Constructor.
*
* @param serialPort the serial port for Z-Wave controller is accessible from
* @param store the persistent store to use for storing/retrieving node information
*/
public NettyZWaveController(String serialPort, PersistentStore store) {
this.serialPort = serialPort;
this.store = store;
}
/*
* ZWaveController methods
*/
@Override
public void setListener(ZWaveControllerListener listener) {
this.listener = listener;
}
public void start() {
if (serial == null) {
// Choose a available library
try{
Class.forName("gnu.io.SerialPort"); // check if RxTx is available
logger.info("RxTx is available, using it as Serial port library");
serial = new NettyRxtxChannelInitializer(serialPort, this);
} catch (ClassNotFoundException e) {
try {
Class.forName("com.fazecast.jSerialComm.SerialPort"); // check if jSerialComm is available
logger.info("jSerialComm is available, using it as Serial port library");
serial = new NettyJSCChannelInitializer(serialPort, this);
} catch (ClassNotFoundException e1) {
throw new RuntimeException("Unable to find Rxtx or jSerialComm lib in classpath", e);
}
}
// set up Netty bootstrap
Bootstrap bootstrap = serial.getBootstrap();
bootstrap.connect(serial.getSocketAddress()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
sendDataFrame(new Version());
sendDataFrame(new MemoryGetId());
sendDataFrame(new InitData());
} else {
onZWaveConnectionFailure(future.cause());
}
}
});
}
}
@Override
public void stop() {
}
@Override
public int getHomeId() {
return homeId;
}
@Override
public byte getNodeId() {
return nodeId;
}
@Override
public String getLibraryVersion() {
return libraryVersion;
}
@Override
public Collection<ZWaveNode> getNodes() {
return nodes;
}
@Override
public ZWaveNode getNode(byte nodeId) {
return nodeMap.get(nodeId);
}
public void sendDataFrame(DataFrame frame) {
serial.getChannel().write(new OutboundDataFrame(frame, true));
}
public void sendDataFrame(DataFrame frame, boolean isListeningNode) {
serial.getChannel().write(new OutboundDataFrame(frame, isListeningNode));
}
@Override
public void sendEvent(Object e) {
serial.getChannel().write(e);
}
/*
* ZWaveControllerListener methods
*/
@Override
public void onZWaveNodeAdded(ZWaveEndpoint node) {
if (listener != null) {
listener.onZWaveNodeAdded(node);
}
}
@Override
public void onZWaveNodeUpdated(ZWaveEndpoint node) {
if (listener != null) {
listener.onZWaveNodeUpdated(node);
}
}
@Override
public void onZWaveConnectionFailure(Throwable t) {
if (listener != null) {
listener.onZWaveConnectionFailure(t);
} else {
logger.error("Connection failure and no listener was set", t);
}
}
@Override
public void onZWaveControllerInfo(String libraryVersion, Integer homeId, Byte nodeId) {
if (listener != null && libraryVersion != null && homeId != null && nodeId != null) {
listener.onZWaveControllerInfo(libraryVersion, homeId, nodeId);
}
}
@Override
public void onZWaveInclusionStarted() {
if (listener != null) {
listener.onZWaveInclusionStarted();
}
}
@Override
public void onZWaveInclusion(NodeInfo nodeInfo, boolean success) {
try {
logger.trace("Inclusion of new node {}", ByteUtil.createString(nodeInfo.getNodeId()));
ZWaveNode node = ZWaveNodeFactory.createNode(nodeInfo, !nodeInfo.hasCommandClass(WakeUpCommandClass.ID), this);
logger.trace("Created new node [{}]: {}", node.getNodeId(), node);
addNode(node);
if (listener != null) {
listener.onZWaveInclusion(nodeInfo, success);
}
} catch (NodeCreationException e) {
logger.error("Unable to create node", e);
}
}
@Override
public void onZWaveInclusionStopped() {
if (listener != null) {
listener.onZWaveInclusionStopped();
}
}
@Override
public void onZWaveExclusionStarted() {
if (listener != null) {
listener.onZWaveExclusionStarted();
}
}
@Override
public void onZWaveExclusion(NodeInfo nodeInfo, boolean success) {
if (listener != null) {
listener.onZWaveExclusion(nodeInfo, success);
}
}
@Override
public void onZWaveExclusionStopped() {
if (listener != null) {
listener.onZWaveExclusionStopped();
}
}
/*
* ZWaveChannelListener methods
*/
@Override
public void onLibraryInfo(String libraryVersion) {
this.libraryVersion = libraryVersion;
onZWaveControllerInfo(libraryVersion, homeId, nodeId);
}
@Override
public void onControllerInfo(int homeId, byte nodeId) {
this.homeId = homeId;
this.nodeId = nodeId;
onZWaveControllerInfo(libraryVersion, homeId, nodeId);
}
@Override
public void onNodeProtocolInfo(byte nodeId, NodeProtocolInfo npi) {
try {
logger.trace("Received protocol info for node {}", nodeId);
ZWaveNode node = store.getNode(nodeId, this);
if (node == null || !node.matchesNodeProtocolInfo(npi)) {
node = ZWaveNodeFactory.createNode(
new NodeInfo(nodeId, npi.getBasicDeviceClass(), npi.getGenericDeviceClass(), npi.getSpecificDeviceClass()),
npi.isListening(),
this
);
logger.trace("Created new node: {}: {}", nodeId, node);
} else {
logger.debug("Node[{}] matches persistent node information; no need to interview", nodeId);
}
addNode(node);
} catch (NodeCreationException e) {
logger.error("Unable to create node", e);
}
}
private void addNode(ZWaveNode node) {
ZWaveNode n = nodeMap.get(node.getNodeId());
if (n != null) {
nodes.remove(n);
nodeMap.remove(node.getNodeId());
}
nodes.add(node);
nodeMap.put(node.getNodeId(), node);
node.startInterview(this);
}
@Override
public void onApplicationCommand(ApplicationCommand applicationCommand) {
ZWaveNode node = nodeMap.get(applicationCommand.getNodeId());
if (node != null) {
node.onApplicationCommand(this, applicationCommand);
if (node.isStarted()) {
onZWaveNodeUpdated(node);
}
} else {
logger.error("Unable to find node: {}", nodeId);
}
}
@Override
public void onApplicationUpdate(ApplicationUpdate applicationUpdate) {
Byte nodeId = applicationUpdate.getNodeId();
if (applicationUpdate.didInfoRequestFail()) {
logger.trace("UPDATE_STATE_NODE_INFO_REQ_FAILED received");
}
if (nodeId != null) {
ZWaveNode node = nodeMap.get(nodeId);
if (node != null) {
node.onApplicationUpdate(this, applicationUpdate);
if (node.isStarted()) {
onZWaveNodeUpdated(node);
}
} else {
logger.error("Unable to find node: {}", nodeId);
}
} else {
logger.error("Unable to determine node to route ApplicationUpdate to");
}
}
@Override
public void onTransactionStarted(TransactionStartedEvent evt) {
logger.trace("Detected start of new transaction: {}", evt.getId());
serial.getChannel().write(evt);
}
@Override
public void onTransactionComplete(TransactionCompletedEvent evt) {
logger.trace("Detected end of transaction: {}", evt.getId());
if (evt instanceof SendDataTransactionCompletedEvent) {
ZWaveNode node = nodeMap.get(evt.getNodeId());
if (node != null) {
node.onSendDataCallback(this, true);
} else {
logger.error("Unable to find node: {}", evt.getNodeId());
}
}
serial.getChannel().write(evt);
}
@Override
public void onTransactionFailed(TransactionFailedEvent evt) {
logger.trace("Detected transaction failure: {}", evt.getId());
if (evt instanceof SendDataTransactionFailedEvent) {
ZWaveNode node = nodeMap.get(evt.getNodeId());
if (node != null) {
node.onSendDataCallback(this, ((SendDataTransactionFailedEvent)evt).isTargetNodeACKReceived());
} else {
logger.error("Unable to find node: {}", evt.getNodeId());
}
}
serial.getChannel().write(evt);
}
@Override
public void onAddNodeToNetwork(AddNodeToNetwork update) {
if (listener != null) {
switch (update.getStatus()) {
case AddNodeToNetwork.ADD_NODE_STATUS_LEARN_READY:
onZWaveInclusionStarted();
break;
case AddNodeToNetwork.ADD_NODE_STATUS_DONE:
onZWaveInclusionStopped();
break;
case AddNodeToNetwork.ADD_NODE_STATUS_ADDING_CONTROLLER:
case AddNodeToNetwork.ADD_NODE_STATUS_ADDING_SLAVE:
onZWaveInclusion(update.getNodeInfo(), true);
break;
case AddNodeToNetwork.ADD_NODE_STATUS_FAILED:
onZWaveInclusion(update.getNodeInfo(), false);
break;
default:
logger.debug("Received unexpected status from AddNodeToNetwork frame: {}", update.getStatus());
}
}
}
@Override
public void onRemoveNodeFromNetwork(RemoveNodeFromNetwork update) {
if (listener != null) {
switch (update.getStatus()) {
case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_LEARN_READY:
onZWaveExclusionStarted();
break;
case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_DONE:
onZWaveExclusionStopped();
break;
case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_NODE_FOUND:
logger.debug("A node has been found that wants to be excluded: {}", ByteUtil.createString(update.getSource()));
break;
case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_REMOVING_CONTROLLER:
case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_REMOVING_SLAVE:
onZWaveExclusion(update.getNodeInfo(), true);
break;
case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_FAILED:
onZWaveExclusion(update.getNodeInfo(), false);
break;
default:
logger.debug("Received unexpected status from RemoveNodeFromNetwork frame: {}", update.getStatus());
}
}
}
@Override
public void onSetDefault() {
logger.info("Z-Wave controller has been reset to factory default");
}
/*
* NodeListener methods
*/
@Override
public void onNodeStarted(ZWaveNode node) {
// save the newly started node
logger.debug("Saving information for node {}", node.getNodeId());
store.saveNode(node);
// when a node moves to the "started" state, alert listeners that it's ready to be added
onZWaveNodeAdded(node);
}
}

View file

@ -1,224 +0,0 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you 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.
*/
package io.netty.channel.jsc;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelOption;
import io.netty.channel.DefaultChannelConfig;
import io.netty.channel.MessageSizeEstimator;
import io.netty.channel.RecvByteBufAllocator;
import java.util.Map;
import static io.netty.channel.jsc.JSCChannelOption.*;
/**
* Default configuration class for jSerialComm device connections.
*/
final class DefaultJSCChannelConfig extends DefaultChannelConfig implements JSCChannelConfig {
private volatile int baudrate = 115200;
private volatile boolean dtr;
private volatile boolean rts;
private volatile Stopbits stopbits = Stopbits.STOPBITS_1;
private volatile int databits = 8;
private volatile Paritybit paritybit = Paritybit.NONE;
private volatile int waitTime;
private volatile int readTimeout = 1000;
DefaultJSCChannelConfig(JSerialCommChannel channel) {
super(channel);
}
@Override
public Map<ChannelOption<?>, Object> getOptions() {
return getOptions(super.getOptions(), BAUD_RATE, DTR, RTS, STOP_BITS, DATA_BITS, PARITY_BIT, WAIT_TIME);
}
@SuppressWarnings("unchecked")
@Override
public <T> T getOption(ChannelOption<T> option) {
if (option == BAUD_RATE)
return (T) Integer.valueOf(getBaudrate());
else if (option == STOP_BITS)
return (T) getStopbits();
else if (option == DATA_BITS)
return (T) Integer.valueOf(getDatabits());
else if (option == PARITY_BIT)
return (T) getParitybit();
else if (option == WAIT_TIME)
return (T) Integer.valueOf(getWaitTimeMillis());
else if (option == READ_TIMEOUT)
return (T) Integer.valueOf(getReadTimeout());
return super.getOption(option);
}
@Override
public <T> boolean setOption(ChannelOption<T> option, T value) {
validate(option, value);
if (option == BAUD_RATE) {
setBaudrate((Integer) value);
} else if (option == STOP_BITS) {
setStopbits((Stopbits) value);
} else if (option == DATA_BITS) {
setDatabits((Integer)value);
} else if (option == PARITY_BIT) {
setParitybit((Paritybit) value);
} else if (option == WAIT_TIME) {
setWaitTimeMillis((Integer) value);
} else if (option == READ_TIMEOUT) {
setReadTimeout((Integer) value);
} else {
return super.setOption(option, value);
}
return true;
}
@Override
public JSCChannelConfig setBaudrate(final int baudrate) {
this.baudrate = baudrate;
return this;
}
@Override
public JSCChannelConfig setStopbits(final Stopbits stopbits) {
this.stopbits = stopbits;
return this;
}
@Override
public JSCChannelConfig setDatabits(final int databits) {
this.databits = databits;
return this;
}
@Override
public JSCChannelConfig setParitybit(final Paritybit paritybit) {
this.paritybit = paritybit;
return this;
}
@Override
public int getBaudrate() {
return baudrate;
}
@Override
public Stopbits getStopbits() {
return stopbits;
}
@Override
public int getDatabits() {
return databits;
}
@Override
public Paritybit getParitybit() {
return paritybit;
}
@Override
public int getWaitTimeMillis() {
return waitTime;
}
@Override
public JSCChannelConfig setWaitTimeMillis(final int waitTimeMillis) {
if (waitTimeMillis < 0) {
throw new IllegalArgumentException("Wait time must be >= 0");
}
waitTime = waitTimeMillis;
return this;
}
@Override
public JSCChannelConfig setReadTimeout(int readTimeout) {
if (readTimeout < 0) {
throw new IllegalArgumentException("readTime must be >= 0");
}
this.readTimeout = readTimeout;
return this;
}
@Override
public int getReadTimeout() {
return readTimeout;
}
@Override
public JSCChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
super.setConnectTimeoutMillis(connectTimeoutMillis);
return this;
}
@Override
@Deprecated
public JSCChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) {
super.setMaxMessagesPerRead(maxMessagesPerRead);
return this;
}
@Override
public JSCChannelConfig setWriteSpinCount(int writeSpinCount) {
super.setWriteSpinCount(writeSpinCount);
return this;
}
@Override
public JSCChannelConfig setAllocator(ByteBufAllocator allocator) {
super.setAllocator(allocator);
return this;
}
@Override
public JSCChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
super.setRecvByteBufAllocator(allocator);
return this;
}
@Override
public JSCChannelConfig setAutoRead(boolean autoRead) {
super.setAutoRead(autoRead);
return this;
}
@Override
public JSCChannelConfig setAutoClose(boolean autoClose) {
super.setAutoClose(autoClose);
return this;
}
@Override
public JSCChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
super.setWriteBufferHighWaterMark(writeBufferHighWaterMark);
return this;
}
@Override
public JSCChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
super.setWriteBufferLowWaterMark(writeBufferLowWaterMark);
return this;
}
@Override
public JSCChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
super.setMessageSizeEstimator(estimator);
return this;
}
}

View file

@ -1,233 +0,0 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you 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.
*/
package io.netty.channel.jsc;
import com.fazecast.jSerialComm.SerialPort;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelConfig;
import io.netty.channel.MessageSizeEstimator;
import io.netty.channel.RecvByteBufAllocator;
/**
* A configuration class for JSerialComm device connections.
*
* <h3>Available options</h3>
*
* In addition to the options provided by {@link ChannelConfig},
* {@link DefaultJSCChannelConfig} allows the following options in the option map:
*
* <table border="1" cellspacing="0" cellpadding="6">
* <tr>
* <th>Name</th><th>Associated setter method</th>
* </tr><tr>
* <td>{@link JSCChannelOption#BAUD_RATE}</td><td>{@link #setBaudrate(int)}</td>
* </tr><tr>
* <td>{@link JSCChannelOption#STOP_BITS}</td><td>{@link #setStopbits(Stopbits)}</td>
* </tr><tr>
* <td>{@link JSCChannelOption#DATA_BITS}</td><td>{@link #setDatabits(int)}</td>
* </tr><tr>
* <td>{@link JSCChannelOption#PARITY_BIT}</td><td>{@link #setParitybit(Paritybit)}</td>
* </tr><tr>
* <td>{@link JSCChannelOption#WAIT_TIME}</td><td>{@link #setWaitTimeMillis(int)}</td>
* </tr>
* </table>
*/
public interface JSCChannelConfig extends ChannelConfig {
enum Stopbits {
/**
* 1 stop bit will be sent at the end of every character
*/
STOPBITS_1(SerialPort.ONE_STOP_BIT),
/**
* 2 stop bits will be sent at the end of every character
*/
STOPBITS_2(SerialPort.TWO_STOP_BITS),
/**
* 1.5 stop bits will be sent at the end of every character
*/
STOPBITS_1_5(SerialPort.ONE_POINT_FIVE_STOP_BITS);
private final int value;
Stopbits(int value) {
this.value = value;
}
public int value() {
return value;
}
public static Stopbits valueOf(int value) {
for (Stopbits stopbit : Stopbits.values()) {
if (stopbit.value == value) {
return stopbit;
}
}
throw new IllegalArgumentException("unknown " + Stopbits.class.getSimpleName() + " value: " + value);
}
}
enum Paritybit {
/**
* No parity bit will be sent with each data character at all
*/
NONE(SerialPort.NO_PARITY),
/**
* An odd parity bit will be sent with each data character, ie. will be set
* to 1 if the data character contains an even number of bits set to 1.
*/
ODD(SerialPort.ODD_PARITY),
/**
* An even parity bit will be sent with each data character, ie. will be set
* to 1 if the data character contains an odd number of bits set to 1.
*/
EVEN(SerialPort.EVEN_PARITY),
/**
* A mark parity bit (ie. always 1) will be sent with each data character
*/
MARK(SerialPort.MARK_PARITY),
/**
* A space parity bit (ie. always 0) will be sent with each data character
*/
SPACE(SerialPort.SPACE_PARITY);
private final int value;
Paritybit(int value) {
this.value = value;
}
public int value() {
return value;
}
public static Paritybit valueOf(int value) {
for (Paritybit paritybit : Paritybit.values()) {
if (paritybit.value == value) {
return paritybit;
}
}
throw new IllegalArgumentException("unknown " + Paritybit.class.getSimpleName() + " value: " + value);
}
}
/**
* Sets the baud rate (ie. bits per second) for communication with the serial device.
* The baud rate will include bits for framing (in the form of stop bits and parity),
* such that the effective data rate will be lower than this value.
*
* @param baudrate The baud rate (in bits per second)
*/
JSCChannelConfig setBaudrate(int baudrate);
/**
* Sets the number of stop bits to include at the end of every character to aid the
* serial device in synchronising with the data.
*
* @param stopbits The number of stop bits to use
*/
JSCChannelConfig setStopbits(Stopbits stopbits);
/**
* Sets the number of data bits to use to make up each character sent to the serial
* device.
*
* @param databits The number of data bits to use
*/
JSCChannelConfig setDatabits(int databits);
/**
* Sets the type of parity bit to be used when communicating with the serial device.
*
* @param paritybit The type of parity bit to be used
*/
JSCChannelConfig setParitybit(Paritybit paritybit);
/**
* @return The configured baud rate, defaulting to 115200 if unset
*/
int getBaudrate();
/**
* @return The configured stop bits, defaulting to {@link Stopbits#STOPBITS_1} if unset
*/
Stopbits getStopbits();
/**
* @return The configured data bits, defaulting to 8 if unset
*/
int getDatabits();
/**
* @return The configured parity bit, defaulting to {@link Paritybit#NONE} if unset
*/
Paritybit getParitybit();
/**
* @return The number of milliseconds to wait between opening the serial port and
* initialising.
*/
int getWaitTimeMillis();
/**
* Sets the time to wait after opening the serial port and before sending it any
* configuration information or data. A value of 0 indicates that no waiting should
* occur.
*
* @param waitTimeMillis The number of milliseconds to wait, defaulting to 0 (no
* wait) if unset
* @throws IllegalArgumentException if the supplied value is &lt; 0
*/
JSCChannelConfig setWaitTimeMillis(int waitTimeMillis);
/**
* Sets the maximal time (in ms) to block while try to read from the serial port. Default is 1000ms
*/
JSCChannelConfig setReadTimeout(int readTimeout);
/**
* Return the maximal time (in ms) to block and wait for something to be ready to read.
*/
int getReadTimeout();
@Override
JSCChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis);
@Override
@Deprecated
JSCChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead);
@Override
JSCChannelConfig setWriteSpinCount(int writeSpinCount);
@Override
JSCChannelConfig setAllocator(ByteBufAllocator allocator);
@Override
JSCChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator);
@Override
JSCChannelConfig setAutoRead(boolean autoRead);
@Override
JSCChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark);
@Override
JSCChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark);
@Override
JSCChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator);
}

View file

@ -1,40 +0,0 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you 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.
*/
package io.netty.channel.jsc;
import io.netty.channel.ChannelOption;
import io.netty.channel.jsc.JSCChannelConfig.Paritybit;
import io.netty.channel.jsc.JSCChannelConfig.Stopbits;
/**
* Option for configuring a serial port connection
*/
public final class JSCChannelOption<T> extends ChannelOption<T> {
public static final ChannelOption<Integer> BAUD_RATE = valueOf("BAUD_RATE");
public static final ChannelOption<Boolean> DTR = valueOf("DTR");
public static final ChannelOption<Boolean> RTS = valueOf("RTS");
public static final ChannelOption<Stopbits> STOP_BITS = valueOf("STOP_BITS");
public static final ChannelOption<Integer> DATA_BITS = valueOf("DATA_BITS");
public static final ChannelOption<Paritybit> PARITY_BIT = valueOf("PARITY_BIT");
public static final ChannelOption<Integer> WAIT_TIME = valueOf("WAIT_TIME");
public static final ChannelOption<Integer> READ_TIMEOUT = valueOf("READ_TIMEOUT");
@SuppressWarnings({ "unused", "deprecation" })
private JSCChannelOption() {
super(null);
}
}

View file

@ -1,45 +0,0 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you 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.
*/
package io.netty.channel.jsc;
import java.net.SocketAddress;
/**
* A {@link SocketAddress} subclass to wrap the serial port address of a jSerialComm
* device (e.g. COM1, /dev/ttyUSB0).
*/
public class JSCDeviceAddress extends SocketAddress {
private static final long serialVersionUID = -2907820090993709523L;
private final String value;
/**
* Creates a JSCDeviceAddress representing the address of the serial port.
*
* @param value the address of the device (e.g. COM1, /dev/ttyUSB0, ...)
*/
public JSCDeviceAddress(String value) {
this.value = value;
}
/**
* @return The serial port address of the device (e.g. COM1, /dev/ttyUSB0, ...)
*/
public String value() {
return value;
}
}

View file

@ -1,181 +0,0 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you 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.
*/
package io.netty.channel.jsc;
import com.fazecast.jSerialComm.SerialPort;
import io.netty.channel.ChannelPromise;
import io.netty.channel.oio.OioByteStreamChannel;
import java.io.IOException;
import java.net.SocketAddress;
import java.util.concurrent.TimeUnit;
import static io.netty.channel.jsc.JSCChannelOption.*;
/**
* A channel to a serial device using the jSerialComm library.
*/
public class JSerialCommChannel extends OioByteStreamChannel {
private static final JSCDeviceAddress LOCAL_ADDRESS = new JSCDeviceAddress("localhost");
private final JSCChannelConfig config;
private boolean open = true;
private JSCDeviceAddress deviceAddress;
private SerialPort serialPort;
public JSerialCommChannel() {
super(null);
config = new DefaultJSCChannelConfig(this);
}
@Override
public JSCChannelConfig config() {
return config;
}
@Override
public boolean isOpen() {
return open;
}
@Override
protected AbstractUnsafe newUnsafe() {
return new JSCUnsafe();
}
@Override
protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
JSCDeviceAddress remote = (JSCDeviceAddress) remoteAddress;
SerialPort commPort = SerialPort.getCommPort(remote.value());
if(!commPort.openPort())
throw new IOException("Could not open port: "+remote.value());
commPort.setComPortTimeouts(
SerialPort.TIMEOUT_READ_BLOCKING, config().getOption(READ_TIMEOUT), 0);
deviceAddress = remote;
serialPort = commPort;
}
protected void doInit() throws Exception {
serialPort.setComPortParameters(
config().getOption(BAUD_RATE),
config().getOption(DATA_BITS),
config().getOption(STOP_BITS).value(),
config().getOption(PARITY_BIT).value()
);
//serialPort.setFlowControl(config().getOption(FLOW_CTRL));
activate(serialPort.getInputStream(), serialPort.getOutputStream());
}
@Override
public JSCDeviceAddress localAddress() {
return (JSCDeviceAddress) super.localAddress();
}
@Override
public JSCDeviceAddress remoteAddress() {
return (JSCDeviceAddress) super.remoteAddress();
}
@Override
protected JSCDeviceAddress localAddress0() {
return LOCAL_ADDRESS;
}
@Override
protected JSCDeviceAddress remoteAddress0() {
return deviceAddress;
}
@Override
protected void doBind(SocketAddress localAddress) throws Exception {
throw new UnsupportedOperationException();
}
@Override
protected void doDisconnect() throws Exception {
doClose();
}
@Override
protected void doClose() throws Exception {
open = false;
try {
super.doClose();
} finally {
if (serialPort != null) {
serialPort.closePort();
serialPort = null;
}
}
}
@Override
protected boolean isInputShutdown() {
return !open;
}
private final class JSCUnsafe extends AbstractUnsafe {
@Override
public void connect(
final SocketAddress remoteAddress,
final SocketAddress localAddress, final ChannelPromise promise) {
if (!promise.setUncancellable() || !isOpen()) {
return;
}
try {
final boolean wasActive = isActive();
doConnect(remoteAddress, localAddress);
int waitTime = config().getOption(WAIT_TIME);
if (waitTime > 0) {
eventLoop().schedule(new Runnable() {
@Override
public void run() {
try {
doInit();
safeSetSuccess(promise);
if (!wasActive && isActive()) {
pipeline().fireChannelActive();
}
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
}
}
}, waitTime, TimeUnit.MILLISECONDS);
} else {
doInit();
safeSetSuccess(promise);
if (!wasActive && isActive()) {
pipeline().fireChannelActive();
}
}
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
}
}
}
}

View file

@ -1,20 +0,0 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you 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.
*/
/**
* A serial and parallel port communication transport based on <a href="http://rxtx.qbang.org/">RXTX</a>.
*/
package io.netty.channel.jsc;

View file

@ -5,22 +5,23 @@ import com.whizzosoftware.wzwave.controller.ZWaveControllerListener;
import com.whizzosoftware.wzwave.controller.netty.NettyZWaveController;
import com.whizzosoftware.wzwave.node.NodeInfo;
import com.whizzosoftware.wzwave.node.ZWaveEndpoint;
import com.whizzosoftware.wzwave.persist.HashMapPersistentStore;
import se.hal.HalContext;
import se.hal.intf.*;
import zutil.log.LogUtil;
import java.io.IOException;
import java.util.logging.Logger;
/**
*
*/
public class HalZWaveController implements HalSensorController, HalEventController, HalAutoScannableController {
public class HalZWaveController implements HalSensorController, HalEventController,
HalAutoScannableController, ZWaveControllerListener {
public static final Logger logger = LogUtil.getLogger();
private ZWaveController controller;
public static void main(String[] args) throws IOException {
NettyZWaveController zwave = new NettyZWaveController("COM5", new HashMapPersistentStore());
public static void main(String[] args) {
NettyZWaveController zwave = new NettyZWaveController("COM3", new HashMapPersistentStore());
zwave.setListener(new ZWaveControllerListener(){
@Override
public void onZWaveNodeAdded(ZWaveEndpoint node) {
@ -81,9 +82,11 @@ public class HalZWaveController implements HalSensorController, HalEventControll
return HalContext.getStringProperty("zwave.com_port") != null;
}
@Override
public void initialize() throws Exception {
//controller = new NettyZWaveController(HalContext.getStringProperty("zwave.com_port"));
//controller.setListener(this);
public void initialize() {
controller = new NettyZWaveController(
HalContext.getStringProperty("zwave.com_port"),
new HashMapPersistentStore());
controller.setListener(this);
controller.start();
}
@ -95,7 +98,55 @@ public class HalZWaveController implements HalSensorController, HalEventControll
////////////// Z-WAVE CODE ////////////////////////
@Override
public void onZWaveNodeAdded(ZWaveEndpoint node) {
logger.finest("onZWaveNodeAdded: "+ node);
}
@Override
public void onZWaveNodeUpdated(ZWaveEndpoint node) {
logger.finest("onZWaveNodeUpdated: "+ node);
}
@Override
public void onZWaveConnectionFailure(Throwable t) {
logger.finest("onZWaveConnectionFailure: "+ t);
}
@Override
public void onZWaveControllerInfo(String libraryVersion, Integer homeId, Byte nodeId) {
logger.finest("onZWaveControllerInfo: "+ libraryVersion+" "+homeId+" "+nodeId);
}
@Override
public void onZWaveInclusionStarted() {
logger.finest("onZWaveInclusionStarted");
}
@Override
public void onZWaveInclusion(NodeInfo nodeInfo, boolean success) {
logger.finest("onZWaveInclusion: "+ nodeInfo + " "+success);
}
@Override
public void onZWaveInclusionStopped() {
logger.finest("onZWaveInclusionStopped");
}
@Override
public void onZWaveExclusionStarted() {
logger.finest("onZWaveExclusionStarted");
}
@Override
public void onZWaveExclusion(NodeInfo nodeInfo, boolean success) {
logger.finest("onZWaveExclusion: "+ nodeInfo + " "+success);
}
@Override
public void onZWaveExclusionStopped() {
logger.finest("onZWaveExclusionStopped");
}
////////////// HAL CODE ////////////////////////

View file

@ -0,0 +1,81 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2018 Ziver Koc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package se.hal.plugin.zwave;
import com.whizzosoftware.wzwave.node.NodeCreationException;
import com.whizzosoftware.wzwave.node.NodeListener;
import com.whizzosoftware.wzwave.node.ZWaveNode;
import com.whizzosoftware.wzwave.node.ZWaveNodeFactory;
import com.whizzosoftware.wzwave.persist.PersistenceContext;
import com.whizzosoftware.wzwave.persist.PersistentStore;
import java.util.HashMap;
import java.util.Map;
/**
* A HashMap implementation of PersistentStore.
*
* @author Ziver Koc
*/
public class HashMapPersistentStore implements PersistentStore, PersistenceContext {
private HashMap<String, HashMap<String,Object>> db;
public HashMapPersistentStore() {
db = new HashMap<>();
}
@Override
public ZWaveNode getNode(byte nodeId, NodeListener listener) throws NodeCreationException {
return ZWaveNodeFactory.createNode(this, nodeId, listener);
}
@Override
public void saveNode(ZWaveNode node) {
node.save(this);
}
@Override
public void close() { }
@Override
public Map<String, Object> getNodeMap(int nodeId) {
return get("" + nodeId);
}
@Override
public Map<String, Object> getCommandClassMap(int nodeId, int commandClassId) {
return get("" + nodeId + "." + commandClassId);
}
private Map<String, Object> get(String key) {
if (!db.containsKey(key))
db.put(key, new HashMap<String, Object>());
return db.get(key);
}
}