Skip to content

Commit

Permalink
Adding a simple logging framework that will let users adapt to any re…
Browse files Browse the repository at this point in the history
…al logger they choose.
  • Loading branch information
Christopher Piggott committed Mar 23, 2015
1 parent 43f853c commit f565f90
Show file tree
Hide file tree
Showing 12 changed files with 435 additions and 114 deletions.
1 change: 0 additions & 1 deletion src/main/java/com/autofrog/xbee/api/XbeeMessageParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,6 @@ private XbeeMessageBase processByte(byte b) {
} catch (Exception e) {
/* Notify of some kind of parsing error */
notifyListenersOfException(new XbeeException());

return null;
} finally {
rxState = RxState.WAITING_FOR_FLAG;
Expand Down
97 changes: 97 additions & 0 deletions src/main/java/com/autofrog/xbee/api/cache/PlantUmlGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package com.autofrog.xbee.api.cache;

import com.autofrog.xbee.api.messages.XbeeNodeDiscovery;

import java.util.Map;

/**
* Generates diagrams and reports from a node database
*
* <p/>
* <pre>
* (C) Copyright 2015 Christopher Piggott (cpiggott@gmail.com)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* 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
* Lesser General Public License for more details.
* </pre>
*/
public class PlantUmlGenerator {

private final XbeeConcurrentDeviceAddressMap addressMap;
private final Map<Integer, XbeeNodeDiscovery> discoveries;

public enum PlantUmlOpts {
SHOW_ALL,
SHOW_NAME,
SHOW_PROFILE,
SHOW_MANUFACTURER,
SHOW_TYPE
}

public PlantUmlGenerator(XbeeConcurrentDeviceAddressMap addressMap, Map<Integer, XbeeNodeDiscovery> discoveries) {
this.addressMap = addressMap;
this.discoveries = discoveries;
}


public String generatePlantUML(PlantUmlOpts... options) {

/*
* Example PlantUML Output
*
* @startuml
*
* skinparam state {
* BackgroundColor<<coordinator>> lightblue
* BackgroundColor<<router>> red
* BackgroundColor<<endDevice>> yellow
* }
* state 01E3 as "Router 01E3" <<coordinator>> {
* 01E3: Coordinator
* 01E3: 0x00A01020340303FD
* 01E3: Manufacturer: 0x0001
* 01E3: Profile ID: 0x0001
* 01E3: Name: xxxHere is its name
* }
* state 01E2 as "Router 01E3" <<router>> {
* 01E2 : Coordinator
* 01E2 : Router
* 01E2 : Manufacturer: 0x0001
* 01E2 : Profile ID: 0x0001
* 01E2 : Name: Here is its name
* }
*
* 01E3 --> 01E2
*
* @enduml
*/


StringBuilder sb = new StringBuilder();

for (int id : discoveries.keySet()) {
XbeeNodeDiscovery d = discoveries.get(id);

String name;

if (d.getDeviceName() != null) {
name = d.getDeviceName();
} else {
name = String.format("%04X", d.getAddress());
}

sb.append(name);
}


return sb.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public synchronized void clear() {
*
* @return copy of this table
*/
public synchronized Map<Integer, byte[]> getMap() {
public synchronized Map<Integer, byte[]> copyMap() {
Map<Integer, byte[]> temp = new HashMap<Integer, byte[]>();
for(int key : forward.keySet()) {
temp.put(key, forward.get(key));
Expand All @@ -73,7 +73,7 @@ public synchronized Map<Integer, byte[]> getMap() {
* value is different than the new address being provided this is an indication
* that the address has changed.
*/
public synchronized int replace(byte[] deviceId, int newAddress) {
public synchronized Integer replace(byte[] deviceId, int newAddress) {
Integer oldAddress = null;

if (deviceId != null) {
Expand All @@ -90,8 +90,15 @@ public synchronized int replace(byte[] deviceId, int newAddress) {
}

if(oldAddress == null) {
/*
* There wasn't an old record, so just put the new one
*/
reverse.put(deviceId, newAddress);
} else if(oldAddress != newAddress) {
/*
* There was an old record - remove it
*/
reverse.remove(oldAddress);
reverse.put(deviceId, newAddress);
} else {
/* Do nothing - they are the same. */
Expand Down
98 changes: 67 additions & 31 deletions src/main/java/com/autofrog/xbee/api/cache/XbeeNodeCache.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
package com.autofrog.xbee.api.cache;

import com.autofrog.xbee.api.listeners.XbeeMessageListener;
import com.autofrog.xbee.api.messages.XbeeAddressableMessage;
import com.autofrog.xbee.api.messages.XbeeExplicitRxMessage;
import com.autofrog.xbee.api.messages.XbeeNodeDiscovery;
import com.autofrog.xbee.api.messages.XbeeRouteRecordIndicator;
import com.autofrog.xbee.api.protocol.XbeeApiConstants;
import com.autofrog.xbee.api.util.XbeeLogListener;
import com.autofrog.xbee.api.util.XbeeLogger;
import com.autofrog.xbee.api.util.XbeeUtilities;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
* A cache of doscpvered device information.
*
* A cache of discovered device information.
* <p/>
* The purpose if this cache is to be able to collect short to long addresses,
* routes, and other node information.
*
* <p/>
* The Xbee modules (including the coordinator) add device IDs to messages when
* possible, but because of memory limitations they cannot do it reliably on very
* large networks.
*
* <p/>
* Part of he challenge is that the 16 bit address of a device can change under certain
* conditions. This includes address conflicts or if a device leaves and rejoins the
* network. Since the 16 bit address is not static, it is not a reliable way to identify
* a device.
*
* <p/>
* <pre>
* (C) Copyright 2015 Christopher Piggott (cpiggott@gmail.com)
*
Expand Down Expand Up @@ -60,35 +65,65 @@ public class XbeeNodeCache {
private final Set<Short> unknownAddresses = Collections.synchronizedSet(new HashSet<Short>());


/**
* Listener of node discovery packets
*/
private final XbeeMessageListener<XbeeNodeDiscovery> discoveryListener = new XbeeMessageListener<XbeeNodeDiscovery>() {
@Override
public void onXbeeMessage(Object sender, XbeeNodeDiscovery msg) {
/* TODO: figure out if the device ID could be invalid in a node discovery packet */
addressMap.replace(msg.getDeviceId(), msg.getAddress());
private final static XbeeLogger log = XbeeLogger.getLogger(XbeeNodeCache.class);

discoveries.put(msg.getAddress(), msg);
}
};
public XbeeAddressableMessage filter(XbeeAddressableMessage input) {

/**
* Listener of route indication messages
*/
private final XbeeMessageListener<XbeeRouteRecordIndicator> routeListener = new XbeeMessageListener<XbeeRouteRecordIndicator>() {
@Override
public void onXbeeMessage(Object sender, XbeeRouteRecordIndicator route) {
/* TODO: figure out if the device id can be invalid in a route record indicator.
* For example, could it be a null address like 0x0000000000000000 or 0xFFFFFFFFFFFFFFFF
* or a broadcast address like 0x000000000000FFFF?
*/
addressMap.replace(route.getDeviceId(), route.getAddress());
final int address = input.getAddress();
final byte[] deviceId = input.getDeviceId();

/* TODO: this is NOT safe - the network (short) address can change */
routes.put(route.getAddress(), route);
final boolean device_id_is_unknown = (Arrays.equals(XbeeApiConstants.UNKNOWN_DEVICE_ID, deviceId));
final boolean device_id_is_known = !device_id_is_unknown;
final boolean device_id_is_broadcast = (Arrays.equals(XbeeApiConstants.BROADCAST_DEVICE_ID, deviceId));

final boolean network_address_is_known = (address != XbeeApiConstants.UNKNOWN_ADDR);
final boolean network_address_is_broadcast = (address == XbeeApiConstants.BROADCAST_ADDR);

final boolean is_broadcast = network_address_is_broadcast || device_id_is_broadcast;
final boolean is_resolved = device_id_is_known && network_address_is_known;
/**
* Do not modify broadcasts.
*/
if (is_broadcast) {
log.log(XbeeLogListener.Level.TRACE, "this is a broadcast", null);
return input;
} else if (is_resolved) {
addressMap.replace(deviceId, address);

if (input instanceof XbeeRouteRecordIndicator) {
XbeeRouteRecordIndicator route = (XbeeRouteRecordIndicator) input;
log.log(XbeeLogListener.Level.DEBUG, "Adding " + route, null);
routes.put(route.getAddress(), route);
}

if (input instanceof XbeeNodeDiscovery) {
XbeeNodeDiscovery discovery = (XbeeNodeDiscovery) input;
log.log(XbeeLogListener.Level.DEBUG, "Adding " + discovery, null);
discoveries.put(input.getAddress(), discovery);
}

/*
* Since this packet came in fully resolved there's nothing else to do
* to it.
*/
return input;
} else {
/*
* This packet did NOT come in fully resolved.
*/
byte[] newDeviceId = addressMap.get(address);
if (newDeviceId != null) {
log.log(XbeeLogListener.Level.TRACE, "Replacing device id", null);
return input.cloneWithNewDeviceId(newDeviceId);
} else {
/*
* We could not find it - nothing to do but return the original message
*/
log.log(XbeeLogListener.Level.TRACE, "Doing nothing", null);
return input;
}
}
};
}

/**
* Listener of route indication messages
Expand All @@ -98,7 +133,7 @@ public void onXbeeMessage(Object sender, XbeeRouteRecordIndicator route) {
public void onXbeeMessage(Object sender, XbeeExplicitRxMessage msg) {

/* TODO: update the address map if the device id has changed */
if(msg.getDeviceId() != null) {
if (msg.getDeviceId() != null) {
addressMap.replace(msg.getDeviceId(), msg.getAddress());
}
}
Expand All @@ -109,4 +144,5 @@ public XbeeNodeDiscovery get(int networkAddress) {
return discoveries.get(networkAddress);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.autofrog.xbee.api.messages;

/**
* <pre>
* (C) Copyright 2015 Christopher Piggott (cpiggott@gmail.com)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* 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
* Lesser General Public License for more details.
* </pre>
*/
public abstract class XbeeAddressableMessage extends XbeeMessageBase {
protected final byte[] deviceId;
protected final int address;


public XbeeAddressableMessage(byte rawFrameType, byte[] deviceId, int address) {
super(rawFrameType);
this.deviceId = deviceId;
this.address = address;
}

/**
* Get the network (16 bit) address of the device.
* @note The 16 bit address is not static. It can change under certain conditions,
* such as an address conflict or when a device leaves then re-joins the network.
* To properly identify a device use its full deviceId.
*
* @return
*/
public final int getAddress() {
return address;
}

public final byte[] getDeviceId() {
return deviceId;
}


/**
* Messages must implement this - essentially a clone of the original message with
* a new network (16-bit) address.
* @param newDeviceId new address
* @return
*/
protected abstract XbeeAddressableMessage doCloneWithNewDeviceId(byte [] newDeviceId);

/**
* Return a copy of the object with a modified network address
* @param newDeviceId
* @return
*/
public XbeeAddressableMessage cloneWithNewDeviceId(byte[] newDeviceId) {
return doCloneWithNewDeviceId(newDeviceId);
}

}
Loading

0 comments on commit f565f90

Please sign in to comment.