translator.py
Go to the documentation of this file.
00001 #! /usr/bin/env python
00002 # -*- coding: utf-8 -*-
00003 #     _____
00004 #    /  _  \
00005 #   / _/ \  \
00006 #  / / \_/   \
00007 # /  \_/  _   \  ___  _    ___   ___   ____   ____   ___   _____  _   _
00008 # \  / \_/ \  / /  _\| |  | __| / _ \ | ┌┐ \ | ┌┐ \ / _ \ |_   _|| | | |
00009 #  \ \_/ \_/ /  | |  | |  | └─┐| |_| || └┘ / | └┘_/| |_| |  | |  | └─┘ |
00010 #   \  \_/  /   | |_ | |_ | ┌─┘|  _  || |\ \ | |   |  _  |  | |  | ┌─┐ |
00011 #    \_____/    \___/|___||___||_| |_||_| \_\|_|   |_| |_|  |_|  |_| |_|
00012 #            ROBOTICS™
00013 #
00014 #
00015 #  Copyright © 2012 Clearpath Robotics, Inc. 
00016 #  All Rights Reserved
00017 #  
00018 # Redistribution and use in source and binary forms, with or without
00019 # modification, are permitted provided that the following conditions are met:
00020 #     * Redistributions of source code must retain the above copyright
00021 #       notice, this list of conditions and the following disclaimer.
00022 #     * Redistributions in binary form must reproduce the above copyright
00023 #       notice, this list of conditions and the following disclaimer in the
00024 #       documentation and/or other materials provided with the distribution.
00025 #     * Neither the name of Clearpath Robotics, Inc. nor the
00026 #       names of its contributors may be used to endorse or promote products
00027 #       derived from this software without specific prior written permission.
00028 # 
00029 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00030 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00031 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00032 # DISCLAIMED. IN NO EVENT SHALL CLEARPATH ROBOTICS, INC. BE LIABLE FOR ANY
00033 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00034 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00035 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00036 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00037 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00038 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00039 #
00040 # Please send comments, questions, or patches to skynet@clearpathrobotics.com
00041 #
00042 
00043 import roslib, roslib.message, roslib.msgs
00044 import genpy
00045 import rospy
00046 import struct
00047 from itertools import izip
00048 from cStringIO import StringIO
00049 
00050 
00051 class EndOfBuffer(BaseException):
00052   pass
00053 
00054 
00055 class TranslatorError(ValueError):
00056   pass
00057 
00058 
00059 class Handler(object):
00060   def field(self, msg):
00061     return getattr(msg, self.name)
00062 
00063   def preserialize(self, msg):
00064     pass
00065 
00066 
00067 class SubMessageHandler(Handler):
00068   def __init__(self, field):
00069     self.name = field.name
00070     self.msg_cls = roslib.message.get_message_class(field.type)
00071 
00072   def deserialize(self, buff, msg):
00073     self.field(msg).translator().deserialize(buff)
00074 
00075   def serialize(self, buff, msg):
00076     self.field(msg).translator().serialize(buff)
00077 
00078 
00079 class FixedFieldsHandler(Handler):
00080   def __init__(self, fields):
00081     struct_strs = ['<']
00082     def pattern(field):
00083       try:
00084         return genpy.base.SIMPLE_TYPES_DICT[field.type]
00085       except KeyError:
00086         if field.base_type in ['uint8', 'char'] and field.array_len is not None:
00087           return "%is" % field.array_len
00088         else:
00089           raise
00090           
00091     struct_strs.extend([pattern(f) for f in fields])
00092     self.struct = struct.Struct(''.join(struct_strs))
00093     self.names = [f.name for f in fields]
00094     self.size = self.struct.size
00095 
00096   def serialize(self, buff, msg):
00097     buff.write(self.struct.pack(*[getattr(msg, name) for name in self.names])) 
00098 
00099   def deserialize(self, buff, msg):
00100     st = buff.read(self.struct.size)
00101     if st == '': raise EndOfBuffer()
00102     values = self.struct.unpack(st) 
00103     for name, value in izip(self.names, values):
00104       setattr(msg, name, value)
00105 
00106 
00107 class SubMessageArrayHandler(Handler):
00108   struct_uint16 = struct.Struct('<H')
00109   struct_uint8 = struct.Struct('<B')
00110 
00111   def __init__(self, field):
00112     self.name = field.name
00113     self.name_count = "%s_count" % self.name
00114     self.msg_cls = roslib.message.get_message_class(field.base_type)
00115     self.submessage_size = self.msg_cls().translator().size
00116 
00117   def deserialize(self, buff, msg):
00118     if hasattr(msg, self.name_count):
00119       # Another field specifies number of array items to deserialize.
00120       length = getattr(msg, self.name_count) * self.submessage_size 
00121       data = StringIO(buff.read(length))
00122     else:
00123       # Consume as much as we can straight from the buffer.
00124       data = buff
00125 
00126     # Find and empty the array to be populated.
00127     array = self.field(msg)
00128     array[:] = []
00129 
00130     try:
00131       while True:
00132         submessage = self.msg_cls()
00133         submessage.translator().deserialize(data)
00134         array.append(submessage)
00135     except EndOfBuffer:
00136       pass
00137 
00138   def serialize(self, buff, msg):
00139     for submessage in self.field(msg):
00140       submessage.translator().serialize(buff)
00141 
00142   def preserialize(self, msg):
00143     if hasattr(msg, self.name_count):
00144       setattr(msg, self.name_count, len(self.field(msg)))
00145 
00146 
00147 class VariableStringHandler(Handler):
00148   struct_bytes = struct.Struct('<H')
00149 
00150   def __init__(self, field):
00151     self.name = field.name
00152 
00153   def deserialize(self, buff, msg):
00154     length = self.struct_bytes.unpack(buff.read(self.struct_bytes.size))[0]
00155     setattr(msg, self.name, str(buff.read(length)))
00156 
00157 
00158 class Translator:
00159   def __init__(self, msg_cls):
00160     self.handlers = []
00161     self.size = None
00162 
00163     cls_name, spec = roslib.msgs.load_by_type(msg_cls._type)
00164 
00165     fixed_fields = []
00166     for field in spec.parsed_fields():
00167       if genpy.base.is_simple(field.base_type) and (field.array_len != None or not field.is_array):
00168         # Simple types and fixed-length character arrays.
00169         fixed_fields.append(field)
00170       else:
00171         # Before dealing with this non-simple field, add a handler for the fixed fields
00172         # encountered so far.
00173         if len(fixed_fields) > 0:
00174           self.handlers.append(FixedFieldsHandler(fixed_fields))
00175           fixed_fields = []
00176 
00177         # Handle this other type.
00178         if field.type == 'string' or (field.base_type == 'uint8' and field.is_array):
00179           self.handlers.append(VariableStringHandler(field))
00180         elif field.is_array:
00181           self.handlers.append(SubMessageArrayHandler(field))
00182         else:
00183           self.handlers.append(SubMessageHandler(field))
00184 
00185     if len(fixed_fields) > 0:
00186       self.handlers.append(FixedFieldsHandler(fixed_fields))
00187 
00188     if len(self.handlers) == 1 and hasattr(self.handlers[0], 'size'):
00189       self.size = self.handlers[0].size
00190 
00191 
00192 class TranslatorProxy:
00193   def __init__(self, translator, msg):
00194     self.translator = translator
00195     self.size = translator.size
00196     self.msg = msg
00197 
00198   def deserialize(self, buff):
00199     try:
00200       for handler in self.translator.handlers:
00201         handler.deserialize(buff, self.msg)
00202     except struct.error as e:
00203       raise TranslatorError(e)
00204 
00205   def serialize(self, buff):
00206     #rospy.loginfo(str(self.msg))
00207     try:
00208       for handler in self.translator.handlers:
00209         handler.serialize(buff, self.msg)
00210     except struct.error as e:
00211       raise TranslatorError(e)
00212 
00213   def preserialize(self):
00214     for handler in self.translator.handlers:
00215       handler.preserialize(self.msg)
00216 
00217 
00218 def translator(self):
00219   if not hasattr(self.__class__, "_translator"):
00220     self.__class__._translator = Translator(self.__class__)
00221   return TranslatorProxy(self.__class__._translator, self)
00222 
00223 roslib.message.Message.translator = translator


applanix_bridge
Author(s): Mike Purvis
autogenerated on Thu Jan 2 2014 11:05:14