-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Christopher Piggott
committed
Mar 10, 2015
1 parent
183b8ac
commit 68778b8
Showing
14 changed files
with
699 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
build | ||
|
||
|
||
.idea | ||
*.iml | ||
|
||
.idea/workspace.xml | ||
.idea/tasks.xml | ||
.idea/dictionaries | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>com.autofrog.xbee</groupId> | ||
<artifactId>xbee-api-java</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<version>4.12</version> | ||
<scope>test</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.easymock</groupId> | ||
<artifactId>easymock</artifactId> | ||
<version>3.3.1</version> | ||
<scope>test</scope> | ||
</dependency> | ||
|
||
</dependencies> | ||
|
||
</project> |
257 changes: 257 additions & 0 deletions
257
src/main/java/com/autofrog/xbee/api/XbeeMessageParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
package com.autofrog.xbee.api; | ||
|
||
import com.autofrog.xbee.api.exceptions.XbeeChecksumException; | ||
import com.autofrog.xbee.api.exceptions.XbeeEmptyMessageException; | ||
import com.autofrog.xbee.api.exceptions.XbeeException; | ||
import com.autofrog.xbee.api.listeners.XbeeMessageListener; | ||
import com.autofrog.xbee.api.listeners.XbeeParsingExceptionListener; | ||
import com.autofrog.xbee.api.messages.XbeeExplicitRxMessage; | ||
import com.autofrog.xbee.api.messages.XbeeMessageBase; | ||
import com.autofrog.xbee.api.protocol.XbeeApiConstants; | ||
import com.autofrog.xbee.api.protocol.XbeeMessageType; | ||
|
||
import java.io.IOException; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.concurrent.CopyOnWriteArrayList; | ||
|
||
/** | ||
* Main entry point for the Xbee API parser. | ||
*/ | ||
public class XbeeMessageParser { | ||
|
||
/** | ||
* States the parser may be in on a byte-by-byte basis | ||
*/ | ||
public enum RxState { | ||
WAITING_FOR_FLAG, | ||
WAITING_FOR_LEN1, | ||
WAITING_FOR_LEN2, | ||
WAIT_FOR_FRAME_TYPE, | ||
COUNTING, | ||
WAITING_FOR_CHECKSUM | ||
} | ||
|
||
protected RxState rxState = RxState.WAITING_FOR_FLAG; | ||
private byte frameType; | ||
private int count; | ||
private int len; | ||
private byte checksum; | ||
private byte[] buf = null; | ||
private boolean escaped = false; | ||
private boolean transmissionPaused = false; | ||
private final Map<XbeeMessageType, List<XbeeMessageListener>> frameTypeSpecificListeners; | ||
private final List<XbeeMessageListener> allFrameTypesListeners; | ||
private final List<XbeeParsingExceptionListener> errorListeners; | ||
|
||
protected XbeeMessageParser() { | ||
frameTypeSpecificListeners = new ConcurrentHashMap<XbeeMessageType, List<XbeeMessageListener>>(); | ||
allFrameTypesListeners = new CopyOnWriteArrayList<XbeeMessageListener>(); | ||
errorListeners = new CopyOnWriteArrayList<XbeeParsingExceptionListener>(); | ||
} | ||
|
||
/** | ||
* Add a listener for ALL xbee messages | ||
* | ||
* @param newListener | ||
*/ | ||
public void addListener(XbeeMessageListener newListener) { | ||
allFrameTypesListeners.add(newListener); | ||
} | ||
|
||
/** | ||
* Add a listener for a specific xbee message type | ||
* | ||
* @param frameType | ||
* @param newListener | ||
*/ | ||
public void addListener(XbeeMessageType frameType, XbeeMessageListener newListener) { | ||
|
||
if (frameTypeSpecificListeners.containsKey(frameType) == false) { | ||
frameTypeSpecificListeners.put(frameType, new CopyOnWriteArrayList<XbeeMessageListener>()); | ||
} | ||
|
||
frameTypeSpecificListeners.get(frameType).add(newListener); | ||
} | ||
|
||
/** | ||
* Remove a listener from everything it's subscribed to | ||
* | ||
* @param listenerToRemove | ||
*/ | ||
public void removeListener(XbeeMessageListener listenerToRemove) { | ||
allFrameTypesListeners.remove(listenerToRemove); | ||
|
||
for (List<XbeeMessageListener> list : frameTypeSpecificListeners.values()) { | ||
list.remove(listenerToRemove); | ||
} | ||
} | ||
|
||
|
||
public void addXbeeExceptionListener(XbeeParsingExceptionListener listener) { | ||
errorListeners.add(listener); | ||
} | ||
|
||
public void removeXbeeExceptionListener(XbeeParsingExceptionListener listener) { | ||
errorListeners.remove(listener); | ||
} | ||
|
||
protected void notifyListenersOfException(XbeeException e) { | ||
for (XbeeParsingExceptionListener listener : errorListeners) { | ||
listener.xbeeParsingError(this, e); | ||
} | ||
} | ||
|
||
protected void notifyListeners(XbeeMessageBase msg) { | ||
for (XbeeMessageListener l : allFrameTypesListeners) { | ||
l.onXbeeMessage(this, msg); | ||
} | ||
|
||
List<XbeeMessageListener> specificListeners = frameTypeSpecificListeners.get(msg.getRawFrameType()); | ||
if (specificListeners != null) { | ||
for (XbeeMessageListener specificListener : specificListeners) { | ||
specificListener.onXbeeMessage(this, msg); | ||
} | ||
} | ||
} | ||
|
||
public void byteIn(byte b) { | ||
XbeeMessageBase msg = processByte(b); | ||
if (msg != null) { | ||
notifyListeners(msg); | ||
} | ||
} | ||
|
||
public void bytesIn(byte[] bytes) { | ||
for (byte b : bytes) { | ||
byteIn(b); | ||
} | ||
} | ||
|
||
public void bytesIn(byte[] bytes, int start, int len) { | ||
int end = start + len; | ||
for (int i = start; i < end; i++) { | ||
byteIn(bytes[i]); | ||
} | ||
} | ||
|
||
/** | ||
* The main state machine | ||
* @param b | ||
* @return | ||
*/ | ||
private XbeeMessageBase processByte(byte b) { | ||
switch (b) { | ||
case XbeeApiConstants.API_FLAG: | ||
if (rxState != RxState.WAITING_FOR_FLAG) { | ||
/* We did not expect two flags in a row */ | ||
notifyListenersOfException(new XbeeEmptyMessageException()); | ||
} | ||
|
||
rxState = RxState.WAITING_FOR_LEN1; | ||
break; | ||
case XbeeApiConstants.API_ESCAPE: | ||
escaped = true; | ||
break; | ||
case XbeeApiConstants.API_XON: | ||
transmissionPaused = false; | ||
break; | ||
case XbeeApiConstants.API_XOFF: | ||
transmissionPaused = true; | ||
break; | ||
|
||
default: | ||
if (escaped) { | ||
b = (byte) (b ^ 0x20); | ||
escaped = false; | ||
} | ||
|
||
switch (rxState) { | ||
case WAITING_FOR_FLAG: | ||
break; | ||
|
||
case WAITING_FOR_LEN1: | ||
len = b << 8; | ||
rxState = RxState.WAITING_FOR_LEN2; | ||
|
||
break; | ||
|
||
case WAITING_FOR_LEN2: | ||
len = len | b; | ||
buf = new byte[len - 1]; | ||
count = 0; | ||
rxState = RxState.WAIT_FOR_FRAME_TYPE; | ||
break; | ||
|
||
case WAIT_FOR_FRAME_TYPE: | ||
frameType = b; | ||
checksum = frameType; | ||
rxState = RxState.COUNTING; | ||
break; | ||
|
||
case COUNTING: | ||
buf[count++] = b; | ||
checksum = (byte) ((checksum + b) & 0xFF); | ||
/* This is len-1 to skip the frame type */ | ||
if (count >= (len-1)) { | ||
rxState = RxState.WAITING_FOR_CHECKSUM; | ||
} | ||
break; | ||
|
||
case WAITING_FOR_CHECKSUM: | ||
byte expected = (byte) (0xFF - checksum); | ||
if (expected == b) { | ||
|
||
try { | ||
return buildSpecificMessage(frameType, buf); | ||
} catch ( Exception e) { | ||
/* Notify of some kind of parsing error */ | ||
notifyListenersOfException(new XbeeException()); | ||
|
||
return null; | ||
} finally { | ||
rxState = RxState.WAITING_FOR_FLAG; | ||
} | ||
|
||
} else { | ||
/* Notify of a checksum error */ | ||
notifyListenersOfException(new XbeeChecksumException()); | ||
rxState = RxState.WAITING_FOR_FLAG; | ||
} | ||
|
||
} | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* Get the RX state on a byte by byte basis. Only really useful for debugging. | ||
* | ||
* @return | ||
*/ | ||
public RxState getRxState() { | ||
return rxState; | ||
} | ||
|
||
private XbeeMessageBase buildSpecificMessage(byte frameType, byte[] buf) throws IOException { | ||
XbeeMessageType type = XbeeMessageType.lookup(frameType); | ||
|
||
switch (type) { | ||
case EXPLICIT_RX: | ||
return XbeeExplicitRxMessage.create(buf); | ||
case NODE_DISCOVERY: | ||
break; | ||
case RX_IO_SAMPLE: | ||
break; | ||
default: | ||
|
||
} | ||
return null; | ||
} | ||
|
||
public String dumpParserState() { | ||
return String.format("state=%s len=%d count=%d escaped=%s", | ||
rxState, len, count, escaped); | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/main/java/com/autofrog/xbee/api/exceptions/XbeeChecksumException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.autofrog.xbee.api.exceptions; | ||
|
||
/** | ||
* Created by chrisp on 009 3/9/2015. | ||
*/ | ||
public class XbeeChecksumException extends XbeeException { | ||
public XbeeChecksumException() { | ||
} | ||
|
||
public XbeeChecksumException(String message) { | ||
super(message); | ||
} | ||
|
||
public XbeeChecksumException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
|
||
public XbeeChecksumException(Throwable cause) { | ||
super(cause); | ||
} | ||
|
||
public XbeeChecksumException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { | ||
super(message, cause, enableSuppression, writableStackTrace); | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/main/java/com/autofrog/xbee/api/exceptions/XbeeEmptyMessageException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.autofrog.xbee.api.exceptions; | ||
|
||
/** | ||
* Created by chrisp on 009 3/9/2015. | ||
*/ | ||
public class XbeeEmptyMessageException extends XbeeException { | ||
public XbeeEmptyMessageException() { | ||
} | ||
|
||
public XbeeEmptyMessageException(String message) { | ||
super(message); | ||
} | ||
|
||
public XbeeEmptyMessageException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
|
||
public XbeeEmptyMessageException(Throwable cause) { | ||
super(cause); | ||
} | ||
|
||
public XbeeEmptyMessageException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { | ||
super(message, cause, enableSuppression, writableStackTrace); | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
src/main/java/com/autofrog/xbee/api/exceptions/XbeeException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.autofrog.xbee.api.exceptions; | ||
|
||
/** | ||
* Created by chrisp on 009 3/9/2015. | ||
*/ | ||
public class XbeeException extends Exception { | ||
|
||
public XbeeException() { | ||
} | ||
|
||
public XbeeException(String message) { | ||
super(message); | ||
} | ||
|
||
public XbeeException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
|
||
public XbeeException(Throwable cause) { | ||
super(cause); | ||
} | ||
|
||
public XbeeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { | ||
super(message, cause, enableSuppression, writableStackTrace); | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/main/java/com/autofrog/xbee/api/listeners/XbeeMessageListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.autofrog.xbee.api.listeners; | ||
|
||
import com.autofrog.xbee.api.messages.XbeeMessageBase; | ||
|
||
/** | ||
* | ||
* @author chrisp | ||
*/ | ||
public interface XbeeMessageListener { | ||
|
||
public void onXbeeMessage(Object sender, XbeeMessageBase msg); | ||
|
||
} |
Oops, something went wrong.