org.ogema.driver.xbee.XBeeDriver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xbee Show documentation
Show all versions of xbee Show documentation
Low-level xbee device driver
The newest version!
/**
* Copyright 2011-2019 Fraunhofer-Gesellschaft zur Förderung der angewandten Wissenschaften e.V.
*
* This file is part of OGEMA.
*
* OGEMA is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* as published by the Free Software Foundation.
*
* OGEMA 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 Lesser General Public License
* along with OGEMA. If not, see .
*/
package org.ogema.driver.xbee;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.ogema.core.channelmanager.driverspi.ChannelDriver;
import org.ogema.core.channelmanager.driverspi.ChannelLocator;
import org.ogema.core.channelmanager.driverspi.ChannelScanListener;
import org.ogema.core.channelmanager.driverspi.ChannelUpdateListener;
import org.ogema.core.channelmanager.driverspi.DeviceListener;
import org.ogema.core.channelmanager.driverspi.DeviceLocator;
import org.ogema.core.channelmanager.driverspi.DeviceScanListener;
import org.ogema.core.channelmanager.driverspi.NoSuchChannelException;
import org.ogema.core.channelmanager.driverspi.NoSuchDeviceException;
import org.ogema.core.channelmanager.driverspi.NoSuchInterfaceException;
import org.ogema.core.channelmanager.driverspi.SampledValueContainer;
import org.ogema.core.channelmanager.driverspi.ValueContainer;
import org.ogema.core.channelmanager.measurements.Value;
import org.ogema.core.hardwaremanager.HardwareDescriptor;
import org.ogema.core.hardwaremanager.HardwareDescriptor.HardwareType;
import org.ogema.core.hardwaremanager.HardwareListener;
import org.ogema.core.hardwaremanager.HardwareManager;
import org.ogema.core.hardwaremanager.SerialHardwareDescriptor;
import org.ogema.core.hardwaremanager.UsbHardwareDescriptor;
import org.ogema.driver.xbee.manager.Endpoint;
import org.ogema.driver.xbee.manager.RemoteDevice;
import org.ogema.driver.xbee.manager.RemoteDevice.InitStates;
import org.ogema.driver.xbee.manager.SimpleDescriptor;
import org.slf4j.Logger;
import jssc.SerialPortException;
public class XBeeDriver implements ChannelDriver, HardwareListener {
private final Map connectionsMap;
private final String driverId = "xbee-driver";
private final String description = "ZigBee driver for Series 2 XBees in API Mode";
private final Map> listenerMap;
private final Logger logger = org.slf4j.LoggerFactory.getLogger("xbee-driver");
public XBeeDriver(HardwareManager hwMngr) {
connectionsMap = new ConcurrentHashMap<>();
listenerMap = new ConcurrentHashMap<>();
hwMngr.addListener(this);
try {
// Check if the portname property is set
String portName = System.getProperty(Constants.STATIC_IF_NAME);
if (portName != null) {
Connection con = new Connection(portName, this);
if (con.localDevice != null)
addConnection(con);
}
else {
Collection descriptors = hwMngr.getHardwareDescriptors(".+:0403:6001:");
for (HardwareDescriptor descr : descriptors) {
portName = ((UsbHardwareDescriptor) descr).getPortName();
if (portName != null) {
Connection con = new Connection(portName, this);
if (con.localDevice != null)
addConnection(con);
}
}
}
} catch (SerialPortException e) {
}
}
protected void removeConnection(String interfaceId) {
connectionsMap.remove(interfaceId);
}
protected void addConnection(Connection con) {
connectionsMap.put(con.getInterfaceId(), con);
logger.debug("New connection {}", con);
}
protected Map getConnections() {
return connectionsMap;
}
protected Connection findConnection(String interfaceId) {
return connectionsMap.get(interfaceId);
}
@Override
public String getDriverId() {
return driverId;
}
@Override
public String getDescription() {
return description;
}
/**
* Scan for initialized devices.
*/
@Override
public void startDeviceScan(String interfaceId, String filter, DeviceScanListener listener)
throws UnsupportedOperationException, NoSuchInterfaceException, IOException {
// TODO filter (XBee, ZigBee, deviceId, modelType...)
boolean success = false;
Connection connection = null;
if (interfaceId != null) {
connection = connectionsMap.get(interfaceId);
if (connection == null)
logger.error("There is no connection established over the specified interface.");
else
success = scanConnection(connection, listener);
}
else {
Set> connections = connectionsMap.entrySet();
if (connections.size() <= 0)
logger.debug("Currently there are no connections alive to ZigBee coordinator hardware.");
else
for (Entry con : connections) {
success = scanConnection(con.getValue(), listener);
}
}
// TODO timer loop
listener.finished(success, null);
}
private boolean scanConnection(Connection connection, DeviceScanListener listener) {
if (connection == null || connection.localDevice == null) {
logger.error("No coordinator hardware seems to be pluged in. Please plug your XSTICK in.");
return false;
}
boolean success = false;
// TODO wait for the initiated network scan/device initialization to finish? Timer? How long?
for (Map.Entry deviceEntry : connection.localDevice.getDevices().entrySet()) {
RemoteDevice remoteDevice = deviceEntry.getValue();
if (remoteDevice.getInitState() == InitStates.INITIALIZED) {
for (Map.Entry endpointEntry : remoteDevice.getEndpoints().entrySet()) {
// @HACK Only devices that support On/Off cluster are reported.
// TODO Each tripple of (addres64Bit, endpoint, cluster) should be reported so the high level driver
// could filter the devices.
if (!endpointEntry.getValue().getClusters().containsKey((short) 6))
continue;
String deviceType = remoteDevice.getDeviceType();
String nodeIdentifier = remoteDevice.getNodeIdentifier();
if (nodeIdentifier == null)
continue; // not realy initialized
String deviceId = null;
String profileId = null;
SimpleDescriptor sd = endpointEntry.getValue().getSimpleDescriptor();
short devID = sd.getApplicationDeviceId();
if (sd != null) {
deviceId = Integer.toHexString(devID & 0xffff);
deviceId = ("0000" + deviceId).substring(deviceId.length());
profileId = Integer.toHexString(sd.getApplicationProfileId() & 0xffff);
profileId = ("0000" + profileId).substring(profileId.length()); // Needed for leading 0s
} // Needed for leading 0s
String address64Bit = Long.toHexString(remoteDevice.getAddress64Bit());
address64Bit = ("0000000000000000" + address64Bit).substring(address64Bit.length()); // Needed for
// leading
// 0s
String endpointId = Integer.toHexString(endpointEntry.getKey() & 0xff);
endpointId = ("00" + endpointId).substring(endpointId.length());
String deviceDescription = Constants.getDeviceDescription(devID, address64Bit + "_" + endpointId);
String parameters = deviceType + ":" + /* nodeIdentifier */deviceDescription + ":" + deviceId + ":"
+ profileId;
DeviceLocator deviceLocator = new DeviceLocator(driverId, connection.getInterfaceId(),
address64Bit + ":" + endpointId, parameters);
listener.deviceFound(deviceLocator);
success = true;
}
}
}
return success;
}
@Override
public void abortDeviceScan(String interfaceId, String filter) {
throw new UnsupportedOperationException();
}
@Override
public void startChannelScan(DeviceLocator device, ChannelScanListener listener)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public List getChannelList(DeviceLocator device) throws UnsupportedOperationException {
return connectionsMap.get(device.getInterfaceName()).findDevice(device).getChannelLocators();
}
@Override
public void readChannels(List channels) throws UnsupportedOperationException, IOException {
for (SampledValueContainer container : channels) {
ChannelLocator channelLocator = container.getChannelLocator();
try {
Connection con = findConnection(channelLocator.getDeviceLocator().getInterfaceName());
Device dev = con.findDevice(channelLocator.getDeviceLocator());
Channel channel = dev.findChannel(channelLocator);
// read data
container.setSampledValue(channel.readValue(con));
} catch (NullPointerException e) {
throw new IOException("Unknown channel: " + channelLocator, e);
}
}
}
@Override
public void listenChannels(List channels, ChannelUpdateListener listener)
throws UnsupportedOperationException, NoSuchDeviceException, NoSuchChannelException, IOException {
if (listener == null) { // TODO check: correct clean up?
listenerMap.clear();
return;
}
if (Configuration.DEBUG)
logger.trace("listenChannels");
List channelList = listenerMap.get(listener);
if (channelList == null) { // remove old channels
channelList = new ArrayList();
}
for (SampledValueContainer container : channels) {
ChannelLocator channelLocator = container.getChannelLocator();
try {
Connection con = findConnection(channelLocator.getDeviceLocator().getInterfaceName());
Device dev = con.findDevice(channelLocator.getDeviceLocator());
if (dev == null) { // create device if it doesn't exist
channelAdded(channelLocator);
dev = con.findDevice(channelLocator.getDeviceLocator());
}
Channel channel = dev.findChannel(channelLocator);
if (channel == null) { // create channel if it doesn't exist
channelAdded(channelLocator);
channel = dev.findChannel(channelLocator);
}
if (!channelLocator.getChannelAddress().split(":")[1].equals("COMMAND")) {
channel.setUpdateListener(container, listener);
channelList.add(channel);
}
} catch (NullPointerException e) {
throw new IOException("Unknown channel: " + channelLocator, e);
}
}
listenerMap.put(listener, channelList);
}
@Override
public void writeChannels(List channels)
throws UnsupportedOperationException, IOException, NoSuchDeviceException, NoSuchChannelException {
for (ValueContainer container : channels) {
ChannelLocator channelLocator = container.getChannelLocator();
try {
Connection con = findConnection(channelLocator.getDeviceLocator().getInterfaceName());
Device dev = con.findDevice(channelLocator.getDeviceLocator());
Channel channel = dev.findChannel(channelLocator);
channel.writeValue(con, container.getValue());
} catch (NullPointerException e) {
throw new IOException("Unknown channel: " + channelLocator, e);
}
}
}
@Override
public void channelAdded(ChannelLocator channelLocator) {
DeviceLocator deviceLocator = channelLocator.getDeviceLocator();
String iface = deviceLocator.getInterfaceName();
Connection con;
Device device;
Channel channel;
// Connection handling
con = findConnection(iface);
if (con == null) {
try {
con = new Connection(iface, this);
addConnection(con);
} catch (SerialPortException e) {
e.printStackTrace();
}
}
// Device handling
device = con.findDevice(deviceLocator);
if (device == null) {
device = new Device(deviceLocator, con);
con.addDevice(device);
}
// Channel handling
channel = device.findChannel(channelLocator);
if (channel == null) {
channel = Channel.createChannel(channelLocator, device);
device.addChannel(channel);
}
}
@Override
public void channelRemoved(ChannelLocator channelLocator) {
DeviceLocator deviceLocator = channelLocator.getDeviceLocator();
String iface = deviceLocator.getInterfaceName();
Connection con;
Device device;
// Connection handling
con = findConnection(iface);
if (null == con) {
return;
}
// Device handling
device = con.findDevice(deviceLocator);
if (null == device) {
return;
}
device.removeChannel(channelLocator.getChannelAddress());
}
@Override
public void hardwareAdded(HardwareDescriptor descriptor) {
logger.debug("hardware added: " + descriptor.getIdentifier());
String portName = null;
if (descriptor.getHardwareType() == HardwareType.USB) {
portName = ((UsbHardwareDescriptor) descriptor).getPortName();
}
else if (descriptor.getHardwareType() == HardwareType.SERIAL) {
portName = ((SerialHardwareDescriptor) descriptor).getPortName();
}
else {
logger.debug("error, descriptor has unsupported hardware type: " + descriptor.getHardwareType().toString());
}
if (null == portName) {
logger.error("Add device with port name null.");
return;
}
Connection con = null;
try {
con = new Connection(portName, this);
addConnection(con);
} catch (SerialPortException e) {
e.printStackTrace();
}
}
@Override
public void hardwareRemoved(HardwareDescriptor descriptor) {
logger.debug("hardware removed: " + descriptor.getIdentifier().toString());
String portName = null;
if (descriptor.getHardwareType() == HardwareType.USB) {
portName = ((UsbHardwareDescriptor) descriptor).getPortName();
}
else if (descriptor.getHardwareType() == HardwareType.SERIAL) {
portName = ((SerialHardwareDescriptor) descriptor).getPortName();
}
Connection con = connectionsMap.get(portName);
if (con != null)
con.close();
connectionsMap.remove(portName);
}
@Override
public void shutdown() {
Set> connections = connectionsMap.entrySet();
for (Entry con : connections) {
con.getValue().getLocalDevice().close();
}
}
@Override
public void addDeviceListener(DeviceListener listener) {
throw new UnsupportedOperationException(
"DeviceListener are not yet supported by this driver. Use DeviceScanListener instead!");
}
@Override
public void removeDeviceListener(DeviceListener listener) {
throw new UnsupportedOperationException(
"DeviceListener are not yet supported by this driver. Use DeviceScanListener instead!");
}
@Override
public void writeChannel(ChannelLocator channelLocator, Value value)
throws UnsupportedOperationException, IOException, NoSuchDeviceException, NoSuchChannelException {
try {
Connection con = findConnection(channelLocator.getDeviceLocator().getInterfaceName());
Device dev = con.findDevice(channelLocator.getDeviceLocator());
Channel channel = dev.findChannel(channelLocator);
channel.writeValue(con, value);
} catch (NullPointerException e) {
throw new IOException("Unknown channel: " + channelLocator, e);
}
}
}