$search
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