KobukiPacketReader.java
Go to the documentation of this file.
00001 /*
00002         Copyright (c) 2013 - York College of Pennsylvania, Patrick J. Martin
00003         The MIT License
00004         See license.txt for details.
00005 */
00006 
00007 package com.github.c77.base_driver.kobuki;
00008 import org.apache.commons.codec.binary.Hex;
00009 import org.apache.commons.logging.Log;
00010 import org.apache.commons.logging.LogFactory;
00011 
00012 import java.nio.ByteBuffer;
00013 import java.util.Arrays;
00014 
00015 public class KobukiPacketReader {
00016 
00017     Log log = LogFactory.getLog(KobukiPacketReader.class);
00018 
00019     //kobuki sensors read from here to update. Accessible fields
00020         private byte[] sensorPacket = new byte[15];
00021         private byte[] inertialSensorPacket = new byte[4];
00022         private byte[] dockingIRPacket = new byte[3];
00023         private byte[] wheelCurrentPacket = new byte[4];
00024         private enum parserState {
00025                 INIT, PARTIAL, COMPLETE;
00026         }
00027         //Fields for class
00028         private parserState curState;
00029         private volatile byte[] stored;
00030         private int bytesStillNeeded;
00031         private int totalSize;
00032         private int bytesStoredIndex;
00033 
00034         public KobukiPacketReader() {
00035                 curState = parserState.INIT;
00036                 stored = new byte[500]; // Should be big enough for the biggest packets
00037                 bytesStillNeeded = 0;
00038                 totalSize = 0;
00039                 bytesStoredIndex = 0;
00040         }
00041 
00042         public final void newPacket(ByteBuffer buff) { // look for main headers in buffer
00043                 if(curState == parserState.INIT || curState == parserState.COMPLETE) {
00044                         for(int i=0; i < buff.array().length-2; i++){ // currently ignoring -86|85 split case... should be rare
00045                                 if(buff.array()[i] == -86 && buff.array()[i+1] == 85) { // Header 0 and Header 1 means packet
00046                                         curState = parserState.PARTIAL;
00047                                         if((buff.array().length-i) >= (buff.array()[i+2]+4)) { // Whole packet is in the buffer. +3 accounts for headers and size. Don't think this is right. Change(+4 for checksum)
00048                                                 byte[] packet = new byte[byteToInt(buff.array()[i+2])+2]; // make byte array of proper size. +1 just in case!!!! Needs to be + 2 to account for checksum and length
00049                                                 //If x + 2 is the length of the payload, the length of payload + length + check sum = length of payload + 2
00050                                                 System.arraycopy(buff.array(), i + 2, packet, 0, byteToInt(buff.array()[i+2]) + 2); //copy in data needed
00051                                                 if(verifyChecksum(byteToInt(buff.array()[i+2]) + 2, packet)) {
00052                                                         System.arraycopy(packet, 1, packet, 0, packet.length - 1);
00053                                                         goodPacket(byteToInt(buff.array()[i+2]) ,packet); // send goodPacket the array and length of array.  At this point, the packet contains ONLY the payload...
00054                                                 } else {
00055                                                         //packet not valid
00056                                                 }
00057                                                 curState = parserState.COMPLETE;
00058                                         } else {
00059                                                 System.arraycopy(buff.array(), i+2, stored, 0, (buff.array().length-(i+2))); //Copy the partial packet into the stored array (only for partial packets)
00060                                                 bytesStillNeeded = (buff.array()[i+2] + 2) - (buff.array().length-(i+2));
00061                                                 totalSize = buff.array()[i+2] + 2;  //This is the payload length + 2.  This accounts for both the length of the payload byte as well as the checksum byte
00062                                                 bytesStoredIndex = buff.array().length - (i+2); //Basically, in the case of a partial packet, this variable stores the length of the partial packet
00063                                         }
00064                                 }
00065                         }
00066                 } else {
00067                         System.arraycopy(buff.array(), 0, stored, bytesStoredIndex, bytesStillNeeded);  //Copy in the "rest" of the packet
00068                         if(verifyChecksum(totalSize, stored)) {
00069                                 System.arraycopy(stored, 1, stored, 0, stored.length - 1);  //Get the array without the checksum or length
00070                                 goodPacket(totalSize - 2, stored);
00071                         } else {
00072                                 //packet not valid
00073                         }
00074                         curState = parserState.COMPLETE;
00075                 }
00076         }
00077 
00078         private final boolean verifyChecksum(int length, byte[] packet) { //Method for verifying checksum
00079 
00080                 byte checksum = 0;
00081 
00082                 for(int i = 0; i < length - 1; i++) {  //length - 1 so that checksum is not included in total!
00083 
00084                         checksum ^= packet[i];   //XOR's all values in packet EXCEPT: HEADERS AND CHECKSUM
00085                 }
00086 
00087                 if(packet[length - 1] == checksum) { //Ensures that calculated checksum is equal to the checksum found in the packet
00088                         return true;
00089                 } else {
00090                         return false;
00091                 }
00092         }
00093 
00094         private final void goodPacket(int length ,byte[] packet) { // Without first 2 headers, length, or checksum!
00095                 //header
00096                 //size
00097                 //payload
00098 
00099                 int curPlace = 0;
00100                 byte[] toSend = new byte[100];
00101                 System.arraycopy(packet, 0, toSend, 0, (packet[1]+2));
00102                 curPlace = packet[1] + 2;
00103                 sortParts(toSend);
00104 
00105                 for(int i = 0; i < 6; i++) { // seven total packets six left
00106                          Arrays.fill(toSend, (byte)0);
00107                          //Changed from curPlace + 1 to curPlace. Changed last field from curPlace + 2 to packet[curPlace + 1]
00108                          System.arraycopy(packet, curPlace, toSend, 0, packet[curPlace+1] + 2); //Curplace is current index that needs to be accessed. packet[curPlace + 1] + 2 accounts for the size of the payload AND the index + payload size bytes
00109                          curPlace = curPlace + packet[curPlace+1] + 2; //Essentially, the index of the element we just accessed. + the length of the payload + 2 for the index and payload size
00110                          sortParts(toSend);  //Sorts packet array into individual packets (see method)
00111                 }
00112         }
00113 
00114         private final void sortParts(byte[] packet){
00115                 switch(packet[0]){ // Sort by packet[0] (The index of the packet. See kobuki driver page for more info).
00116                         case 1:
00117                                 sensorPacket(packet); // Sorts sensor packet
00118                                 break;
00119                         case 3:
00120                                 dockingIRPacket(packet); //sorts dockingIR packet
00121                                 break;
00122                         case 4:
00123                                 inertialSensorPacket(packet); //Sorts inertial sensor packet
00124                                 break;
00125                         case 6:
00126                                 wheelCurrentPacket(packet); //Sorts wheel current packet
00127                                 break;
00128                         default:
00129                                 break;
00130                 }
00131         }
00132 
00133         private final int byteToInt(byte b) {
00134                 return b & 0xFF;
00135         }
00136 
00137         public final void sensorPacket(byte[] packet) { // Store sensor values from packet
00138                 System.arraycopy(packet, 2, sensorPacket, 0, 15); //Copy packet from incoming byte array
00139         }
00140 
00141         private final void inertialSensorPacket(byte[] packet) {
00142                 System.arraycopy(packet, 2, inertialSensorPacket, 0, 4); //Copy packet from incoming byte array
00143         }
00144 
00145         private final void dockingIRPacket(byte[] packet) {  //Sorts the IR docking packet
00146                 System.arraycopy(packet, 2, dockingIRPacket, 0, 3); //Copy packet from incoming byte array
00147         }
00148 
00149         private final void wheelCurrentPacket(byte[] packet) {  //Sorts wheel current data packet
00150                 System.arraycopy(packet, 2, wheelCurrentPacket, 0, 2); //Copy packet from incoming byte array
00151         }
00152 
00156         public final byte[] getSensorPacket() {
00157                 return sensorPacket;
00158         }
00159 
00163         public final byte[] getInertialSensorPacket() {
00164                 return inertialSensorPacket;
00165         }
00166 
00170         public final byte[] getDockingIRPacket() {
00171                 return dockingIRPacket;
00172         }
00173 
00177         public final byte[] getWheelCurrentPacket() {
00178                 return wheelCurrentPacket;
00179         }
00180 }


android_base_controller
Author(s):
autogenerated on Fri Aug 28 2015 10:04:47