00001 from StringIO import StringIO
00002 from struct import Struct, pack, unpack
00003 import re
00004 import rospy
00005 import roslib
00006 import roslib.message
00007
00008
00009 def parseMessageType(field_string):
00010 match = re.match("(.*)\[([\d]*)\]", field_string)
00011 if match:
00012 num_string = match.group(2)
00013 return (match.group(1), int(num_string))
00014 else:
00015 return (field_string, 1)
00016 def fieldToTopic(field):
00017 field.replace("__", "/")
00018
00019 def msgToStructFormat(msg):
00020 slots = list(msg.__slots__)
00021 slot_types = list(msg._slot_types)
00022 fmt_stream = StringIO()
00023 fmt_stream.write("!")
00024 for slot, slot_type in zip(slots, slot_types):
00025 parsed_type = parseMessageType(slot_type)
00026 field_type = parsed_type[0]
00027 field_length = parsed_type[1]
00028 if field_type == "char":
00029 fmt_stream.write("c" * field_length)
00030 elif field_type == "bool":
00031 fmt_stream.write("?" * field_length)
00032 elif field_type == "int8":
00033 fmt_stream.write("b" * field_length)
00034 elif field_type == "uint8":
00035 fmt_stream.write("B" * field_length)
00036 elif field_type == "int16":
00037 raise Exception("int16 is not supported")
00038 elif field_type == "uint16":
00039 fmt_stream.write("H" * field_length)
00040 elif field_type == "int32":
00041 fmt_stream.write("i" * field_length)
00042 elif field_type == "uint32":
00043 fmt_stream.write("I" * field_length)
00044 elif field_type == "int64":
00045 fmt_stream.write("q" * field_length)
00046 elif field_type == "uint64":
00047 fmt_stream.write("Q" * field_length)
00048 elif field_type == "float32":
00049 fmt_stream.write("f" * field_length)
00050 elif field_type == "float64":
00051 fmt_stream.write("d" * field_length)
00052 elif field_type == "string":
00053 raise Excception("string is not supported!, please use char[static_length]")
00054 elif field_type == "duration" or field_type == "time":
00055 raise Excception("duration and time are not supported")
00056 return fmt_stream.getvalue()
00057
00058 def packableValue(value, value_type):
00059 if value_type == "uint8":
00060 return ord(value)
00061 else:
00062 return value
00063
00064 def packMessage(msg, fmt):
00065 data = []
00066 for slot, slot_type in zip(msg.__slots__, msg._slot_types):
00067 slot_value = getattr(msg, slot)
00068 parsed_type = parseMessageType(slot_type)
00069 field_type = parsed_type[0]
00070 if hasattr(slot_value, "__len__"):
00071 for i in range(len(slot_value)):
00072 data.append(packableValue(slot_value[i], field_type))
00073 else:
00074
00075 data.append(slot_value)
00076 packed = pack(fmt, *data)
00077 return packed
00078
00079 def unpackArrayValue(array, field_type):
00080 if field_type == "bool":
00081 return [v == 1 for v in array]
00082 else:
00083 return array
00084
00085 def unpackValue(val, field_type):
00086 if field_type == "bool":
00087 return val == 1
00088 else:
00089 return val
00090
00091 def unpackMessage(data, fmt, message_class):
00092 unpacked_data = unpack(fmt, data)
00093 msg = message_class()
00094 counter = 0
00095 for slot, slot_type in zip(msg.__slots__, msg._slot_types):
00096 slot_value = getattr(msg, slot)
00097 parsed_type = parseMessageType(slot_type)
00098 field_type = parsed_type[0]
00099 field_length = parsed_type[1]
00100 target_data = unpacked_data[counter:counter + field_length]
00101 if hasattr(slot_value, "__len__"):
00102 setattr(msg, slot, unpackArrayValue(target_data, field_type))
00103 else:
00104 setattr(msg, slot, unpackValue(target_data[0], field_type))
00105 counter = counter + field_length
00106 return msg
00107
00108 def publishersFromMessage(msg, prefix="", latch=False):
00109 ret = []
00110 for slot, slot_type in zip(msg.__slots__, msg._slot_types):
00111 topic_name = prefix + "/" + slot.replace("__", "/")
00112 try:
00113 msg_class = roslib.message.get_message_class(slot_type)
00114 except:
00115 raise Exception("invalid topic type: %s"%slot_type)
00116 ret.append(rospy.Publisher(topic_name, msg_class, latch=latch))
00117 return ret
00118
00119 def decomposeLargeMessage(msg, prefix=""):
00120 ret = dict()
00121 for slot, slot_type in zip(msg.__slots__, msg._slot_types):
00122 topic_name = prefix + "/" + slot.replace("__", "/")
00123 ret[topic_name] = getattr(msg, slot)
00124 return ret
00125
00126
00127 def subscribersFromMessage(msg):
00128 ret = []
00129 for slot, slot_type in zip(msg.__slots__, msg._slot_types):
00130 topic_name = "/" + slot.replace("__", "/")
00131 try:
00132 msg_class = roslib.message.get_message_class(slot_type)
00133 except:
00134 raise Exception("invalid topic type: %s"%slot_type)
00135 ret.append((topic_name, msg_class))
00136 return ret
00137
00138
00139
00140
00141
00142 class LargeDataUDPPacket():
00143 def __init__(self, seq_id, id, num, data, packet_size):
00144 self.id = id
00145 self.seq_id = seq_id
00146 self.num = num
00147 self.data = data
00148 self.packet_size = packet_size
00149 def pack(self):
00150 return pack("!III%ds" % (len(self.data)),
00151 self.seq_id, self.id, self.num, self.data)
00152
00153 @classmethod
00154 def headerSize(cls):
00155 return 4 + 4 + 4
00156 @classmethod
00157 def fromData(cls, data, packet_size):
00158 unpacked = unpack("!III%ds" % (len(data) - cls.headerSize()), data)
00159 ret = cls(unpacked[0], unpacked[1], unpacked[2], unpacked[3],
00160 packet_size)
00161
00162 return ret
00163
00164 def separateBufferIntoPackets(seq_id, buffer, packet_size):
00165 buffer_packet_size = packet_size - LargeDataUDPPacket.headerSize()
00166 num_packet = len(buffer) / buffer_packet_size
00167 if len(buffer) % buffer_packet_size != 0:
00168 num_packet = num_packet + 1
00169 packets = []
00170 for i in range(num_packet):
00171 packets.append(LargeDataUDPPacket(seq_id, i, num_packet,
00172 buffer[i*buffer_packet_size:(i+1)*buffer_packet_size],
00173 packet_size))
00174
00175 return packets