ROSSerial.java
Go to the documentation of this file.
00001 // Software License Agreement (BSD License)
00002 //
00003 // Copyright (c) 2011, Willow Garage, Inc.
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions
00008 // are met:
00009 //
00010 //  * Redistributions of source code must retain the above copyright
00011 //    notice, this list of conditions and the following disclaimer.
00012 //  * Redistributions in binary form must reproduce the above
00013 //    copyright notice, this list of conditions and the following
00014 //    disclaimer in the documentation and/or other materials provided
00015 //    with the distribution.
00016 //  * Neither the name of Willow Garage, Inc. nor the names of its
00017 //    contributors may be used to endorse or promote products derived
00018 //    from this software without specific prior written permission.
00019 //
00020 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 // POSSIBILITY OF SUCH DAMAGE.
00032 // Author: Adam Stambler  <adasta@gmail.com>
00033 package org.ros.rosserial;
00034 
00035 import java.io.BufferedInputStream;
00036 import java.io.IOException;
00037 import java.io.InputStream;
00038 import java.io.OutputStream;
00039 import java.util.Timer;
00040 
00041 import org.ros.message.rosserial_msgs.TopicInfo;
00042 import org.ros.node.Node;
00043 
00049 public class ROSSerial implements Runnable  {
00053         public static final byte[] FLAGS = { (byte) 0xff, (byte) 0xff };
00054 
00059         private static final int MAX_MSG_DATA_SIZE =512;
00060         
00064         private OutputStream ostream;
00065 
00069         private InputStream istream;
00070 
00074         private Node node;
00075 
00079         private Protocol protocol;
00080         
00086         public void setOnNewPublication(TopicRegistrationListener listener) {
00087                 protocol.setOnNewPublication(listener);
00088         }
00089 
00095         public void setOnNewSubcription(TopicRegistrationListener listener) {
00096                 protocol.setOnNewSubcription(listener);
00097         } 
00098         
00099 
00100         public TopicInfo[] getSubscriptions() {
00101                 return protocol.getSubscriptions();
00102         }
00103 
00104         public TopicInfo[] getPublications() {
00105                 return protocol.getPublications();
00106         }
00107         
00111         private boolean running = false;
00112 
00113         // parsing state machine variables/enumes
00114         private enum PACKET_STATE {
00115                 FLAGA, FLAGB, HEADER, DATA, CHECKSUM
00116         };
00117 
00118         private PACKET_STATE packet_state;
00119         private byte[] header = new byte[4];
00120         private byte[] data = new byte[MAX_MSG_DATA_SIZE];
00121         private int data_len = 0;
00122         private int byte_index = 0;;
00123 
00127         Protocol.PacketHandler sendHandler = new Protocol.PacketHandler() {
00128 
00129                 @Override
00130                 public void send(byte[] data) {
00131                         // calculate the checksum
00132                         int chk = 0;
00133                         for (int i = 0; i < data.length; i++)
00134                                 chk += 0xff & data[i];
00135                         chk = 255 - chk % 256;
00136 
00137                         try {
00138                                 ostream.write(FLAGS);
00139                                 ostream.write(data);
00140                                 ostream.write((byte) chk);
00141                         } catch (IOException e) {
00142                                 System.out.println("Exception sending :"
00143                                                 + BinaryUtils.byteArrayToHexString(data));
00144                                 e.printStackTrace();
00145                         }
00146                 }
00147         };
00148 
00149         public ROSSerial(Node nh, InputStream input, OutputStream output) {
00150                 ostream = output;
00151                 istream = input;
00152                 node = nh;
00153 
00154                 protocol = new Protocol(node, sendHandler);
00155 
00156         }
00157 
00161         public void shutdown() {
00162                 running = false;
00163         }
00164 
00170         Timer packet_timeout_timer;
00171         
00175         public void run() {
00176                 
00177                 protocol.negotiateTopics();
00178                 protocol.start();
00179                 
00180                 resetPacket();
00181 
00182                 running = true;
00183 
00184                 // TODO
00185                 // there should be a node.isOk() or something
00186                 // similar so that it stops when ros is gone
00187                 // but node.isOk() does not work, its never true...
00188                 byte[] buffer = new byte[500];
00189                 while (running) {
00190                         try {
00191                                 int ret = istream.read(buffer);
00192                                 for(int i=0; i<ret;i++) {
00193                                         handleByte((byte) (0xff & buffer[i]));
00194                                 }
00195                         } catch (IOException e) {
00196                                 node.getLog().error("Unable to read input stream", e);
00197                                 System.out.println("Unable to read input stream");
00198 
00199                                 if (e.toString().equals("java.io.IOException: No such device")) {
00200                                         node.getLog()
00201                                                         .error("Total IO Failure.  Now exiting ROSSerial iothread.");
00202                                         break;
00203                                 }
00204                                 resetPacket();
00205                         } catch (Exception e) {
00206                                 node.getLog().error("Unable to read input stream", e);
00207                         }
00208                         try {
00209                                 //Sleep prevents continuous polling of istream.
00210                                 //continuous polling kills an inputstream on android
00211                                 Thread.sleep(10);
00212                         } catch (InterruptedException e) {
00213                                 e.printStackTrace();
00214                                 break;
00215                         }
00216                 }
00217                 node.getLog().info("Finished ROSSerial IO Thread");             
00218         }
00219 
00220         /*
00221          * ! reset parsing statemachine
00222          */
00223         private void resetPacket() {
00224                 byte_index = 0;
00225                 data_len = 0;
00226                 packet_state = PACKET_STATE.FLAGA;
00227         }
00228 
00229         /*
00230          * ! handle byte takes an input byte and feeds it into the parsing
00231          * statemachine /param b input byte /return true or falls depending on if
00232          * the byte was successfully parsed
00233          */
00234         private boolean handleByte(byte b) {
00235                 switch (packet_state) {
00236                 case FLAGA:
00237                         if (b == (byte) 0xff)
00238                                 packet_state = PACKET_STATE.FLAGB;
00239                         break;
00240                 case FLAGB:
00241                         if (b == (byte) 0xff) {
00242                                 packet_state = PACKET_STATE.HEADER;
00243                         } else {
00244                                 resetPacket();
00245                                 return false;
00246                         }
00247                         break;
00248                 case HEADER:
00249                         header[byte_index] = b;
00250                         byte_index++;
00251                         if (byte_index == 4) {
00252                                 int len = (int) (header[3] << 8) | (int) (header[2]);
00253                                 data_len = len; // add in the header length
00254                                 byte_index = 0;
00255                                 packet_state = PACKET_STATE.DATA;
00256                         }
00257                         break;
00258                 case DATA:
00259                         data[byte_index] = b;
00260                         byte_index++;
00261                         if (byte_index == data_len) {
00262                                 packet_state = PACKET_STATE.CHECKSUM;
00263                         }
00264                         break;
00265                 case CHECKSUM:
00266                         int chk = (int) (0xff & b);
00267                         for (int i = 0; i < 4; i++)
00268                                 chk += (int) (0xff & header[i]);
00269                         for (int i = 0; i < data_len; i++) {
00270                                 chk += (int) (0xff & data[i]);
00271                         }
00272                         if (chk % 256 != 255) {
00273                                 resetPacket();
00274                                 System.out.println("Checksum failed!");
00275                                 return false;
00276                         } else {
00277                                 int topic_id = (int) header[0] | (int) (header[1]) << 8;
00278                                 resetPacket();
00279                                 protocol.parsePacket(topic_id, data);
00280                         }
00281                         break;
00282                 }
00283                 return true;
00284         }
00285 
00286 }


rosserial_java
Author(s): Adam Stambler
autogenerated on Thu Nov 28 2013 11:51:40