00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 __author__ = "mferguson@willowgarage.com (Michael Ferguson)"
00037
00038 __usage__ = """
00039 make_library.py generates the Arduino rosserial library files. It
00040 requires the location of your arduino libraries folder and the name of
00041 one or more packages for which you want to make libraries.
00042
00043 rosrun rosserial_client make_library.py <output_path> pkg_name [pkg2 pkg3 ...]
00044 """
00045
00046 import roslib; roslib.load_manifest("rosserial_client")
00047 import roslib.gentools, roslib.srvs
00048 import roslib.rospack
00049 import rospy
00050
00051 import os, sys, subprocess, re
00052
00053 def type_to_var(ty):
00054 lookup = {
00055 1 : 'uint8_t',
00056 2 : 'uint16_t',
00057 4 : 'uint32_t',
00058 8 : 'uint64_t',
00059 }
00060 return lookup[ty]
00061
00062
00063
00064
00065 class EnumerationType:
00066 """ For data values. """
00067
00068 def __init__(self, name, ty, value):
00069 self.name = name
00070 self.type = ty
00071 self.value = value
00072
00073 def make_declaration(self, f):
00074 f.write(' enum { %s = %s };\n' % (self.name, self.value))
00075
00076 class PrimitiveDataType:
00077 """ Our datatype is a C/C++ primitive. """
00078
00079 def __init__(self, name, ty, bytes):
00080 self.name = name
00081 self.type = ty
00082 self.bytes = bytes
00083
00084 def make_declaration(self, f):
00085 f.write(' %s %s;\n' % (self.type, self.name) )
00086
00087 def serialize(self, f):
00088 cn = self.name.replace("[","").replace("]","").split(".")[-1]
00089 if self.type != type_to_var(self.bytes):
00090 f.write(' union {\n')
00091 f.write(' %s real;\n' % self.type)
00092 f.write(' %s base;\n' % type_to_var(self.bytes))
00093 f.write(' } u_%s;\n' % cn)
00094 f.write(' u_%s.real = this->%s;\n' % (cn,self.name))
00095 for i in range(self.bytes):
00096 f.write(' *(outbuffer + offset + %d) = (u_%s.base >> (8 * %d)) & 0xFF;\n' % (i, cn, i) )
00097 else:
00098 for i in range(self.bytes):
00099 f.write(' *(outbuffer + offset + %d) = (this->%s >> (8 * %d)) & 0xFF;\n' % (i, self.name, i) )
00100 f.write(' offset += sizeof(this->%s);\n' % self.name)
00101
00102 def deserialize(self, f):
00103 cn = self.name.replace("[","").replace("]","").split(".")[-1]
00104 if self.type != type_to_var(self.bytes):
00105 f.write(' union {\n')
00106 f.write(' %s real;\n' % self.type)
00107 f.write(' %s base;\n' % type_to_var(self.bytes))
00108 f.write(' } u_%s;\n' % cn)
00109 f.write(' u_%s.base = 0;\n' % cn)
00110 for i in range(self.bytes):
00111 f.write(' u_%s.base |= ((%s) (*(inbuffer + offset + %d))) << (8 * %d);\n' % (cn,type_to_var(self.bytes),i,i) )
00112 f.write(' this->%s = u_%s.real;\n' % (self.name, cn) )
00113 else:
00114 f.write(' this->%s = ((%s) (*(inbuffer + offset)));\n' % (self.name,self.type) )
00115 for i in range(self.bytes-1):
00116 f.write(' this->%s |= ((%s) (*(inbuffer + offset + %d))) << (8 * %d);\n' % (self.name,self.type,i+1,i+1) )
00117 f.write(' offset += sizeof(this->%s);\n' % self.name)
00118
00119
00120 class MessageDataType(PrimitiveDataType):
00121 """ For when our data type is another message. """
00122 def serialize(self, f):
00123 f.write(' offset += this->%s.serialize(outbuffer + offset);\n' % self.name)
00124
00125 def deserialize(self, f):
00126 f.write(' offset += this->%s.deserialize(inbuffer + offset);\n' % self.name)
00127
00128
00129 class Float64DataType(PrimitiveDataType):
00130 """ AVR C/C++ has no native 64-bit support, we automatically convert to 32-bit float. """
00131
00132 def make_declaration(self, f):
00133 f.write(' float %s;\n' % self.name )
00134
00135 def serialize(self, f):
00136 cn = self.name.replace("[","").replace("]","")
00137 f.write(' int32_t * val_%s = (long *) &(this->%s);\n' % (cn,self.name))
00138 f.write(' int32_t exp_%s = (((*val_%s)>>23)&255);\n' % (cn,cn))
00139 f.write(' if(exp_%s != 0)\n' % cn)
00140 f.write(' exp_%s += 1023-127;\n' % cn)
00141 f.write(' int32_t sig_%s = *val_%s;\n' % (cn,cn))
00142 f.write(' *(outbuffer + offset++) = 0;\n')
00143 f.write(' *(outbuffer + offset++) = 0;\n')
00144 f.write(' *(outbuffer + offset++) = 0;\n')
00145 f.write(' *(outbuffer + offset++) = (sig_%s<<5) & 0xff;\n' % cn)
00146 f.write(' *(outbuffer + offset++) = (sig_%s>>3) & 0xff;\n' % cn)
00147 f.write(' *(outbuffer + offset++) = (sig_%s>>11) & 0xff;\n' % cn)
00148 f.write(' *(outbuffer + offset++) = ((exp_%s<<4) & 0xF0) | ((sig_%s>>19)&0x0F);\n' % (cn,cn))
00149 f.write(' *(outbuffer + offset++) = (exp_%s>>4) & 0x7F;\n' % cn)
00150 f.write(' if(this->%s < 0) *(outbuffer + offset -1) |= 0x80;\n' % self.name)
00151
00152 def deserialize(self, f):
00153 cn = self.name.replace("[","").replace("]","")
00154 f.write(' uint32_t * val_%s = (uint32_t*) &(this->%s);\n' % (cn,self.name))
00155 f.write(' offset += 3;\n')
00156 f.write(' *val_%s = ((uint32_t)(*(inbuffer + offset++))>>5 & 0x07);\n' % cn)
00157 f.write(' *val_%s |= ((uint32_t)(*(inbuffer + offset++)) & 0xff)<<3;\n' % cn)
00158 f.write(' *val_%s |= ((uint32_t)(*(inbuffer + offset++)) & 0xff)<<11;\n' % cn)
00159 f.write(' *val_%s |= ((uint32_t)(*(inbuffer + offset)) & 0x0f)<<19;\n' % cn)
00160 f.write(' uint32_t exp_%s = ((uint32_t)(*(inbuffer + offset++))&0xf0)>>4;\n' % cn)
00161 f.write(' exp_%s |= ((uint32_t)(*(inbuffer + offset)) & 0x7f)<<4;\n' % cn)
00162 f.write(' if(exp_%s !=0)\n' % cn)
00163 f.write(' *val_%s |= ((exp_%s)-1023+127)<<23;\n' % (cn,cn))
00164 f.write(' if( ((*(inbuffer+offset++)) & 0x80) > 0) this->%s = -this->%s;\n' % (self.name,self.name))
00165
00166
00167 class StringDataType(PrimitiveDataType):
00168 """ Need to convert to signed char *. """
00169
00170 def make_declaration(self, f):
00171 f.write(' char * %s;\n' % self.name)
00172
00173 def serialize(self, f):
00174 cn = self.name.replace("[","").replace("]","")
00175 f.write(' uint32_t * length_%s = (uint32_t *)(outbuffer + offset);\n' % cn)
00176 f.write(' *length_%s = strlen( (const char*) this->%s);\n' % (cn,self.name))
00177 f.write(' offset += 4;\n')
00178 f.write(' memcpy(outbuffer + offset, this->%s, *length_%s);\n' % (self.name,cn))
00179 f.write(' offset += *length_%s;\n' % cn)
00180
00181 def deserialize(self, f):
00182 cn = self.name.replace("[","").replace("]","")
00183 f.write(' uint32_t length_%s = *(uint32_t *)(inbuffer + offset);\n' % cn)
00184 f.write(' offset += 4;\n')
00185 f.write(' for(unsigned int k= offset; k< offset+length_%s; ++k){\n'%cn)
00186 f.write(' inbuffer[k-1]=inbuffer[k];\n')
00187 f.write(' }\n')
00188 f.write(' inbuffer[offset+length_%s-1]=0;\n'%cn)
00189 f.write(' this->%s = (char *)(inbuffer + offset-1);\n' % self.name)
00190 f.write(' offset += length_%s;\n' % cn)
00191
00192
00193 class TimeDataType(PrimitiveDataType):
00194
00195 def __init__(self, name, ty, bytes):
00196 self.name = name
00197 self.type = ty
00198 self.sec = PrimitiveDataType(name+'.sec','uint32_t',4)
00199 self.nsec = PrimitiveDataType(name+'.nsec','uint32_t',4)
00200
00201 def make_declaration(self, f):
00202 f.write(' %s %s;\n' % (self.type, self.name))
00203
00204 def serialize(self, f):
00205 self.sec.serialize(f)
00206 self.nsec.serialize(f)
00207
00208 def deserialize(self, f):
00209 self.sec.deserialize(f)
00210 self.nsec.deserialize(f)
00211
00212
00213 class ArrayDataType(PrimitiveDataType):
00214
00215 def __init__(self, name, ty, bytes, cls, array_size=None):
00216 self.name = name
00217 self.type = ty
00218 self.bytes = bytes
00219 self.size = array_size
00220 self.cls = cls
00221
00222 def make_declaration(self, f):
00223 c = self.cls("*"+self.name, self.type, self.bytes)
00224 if self.size == None:
00225 f.write(' uint8_t %s_length;\n' % self.name)
00226 f.write(' %s st_%s;\n' % (self.type, self.name))
00227 f.write(' %s * %s;\n' % (self.type, self.name))
00228 else:
00229 f.write(' %s %s[%d];\n' % (self.type, self.name, self.size))
00230
00231 def serialize(self, f):
00232 c = self.cls(self.name+"[i]", self.type, self.bytes)
00233 if self.size == None:
00234
00235 f.write(' *(outbuffer + offset++) = %s_length;\n' % self.name)
00236 f.write(' *(outbuffer + offset++) = 0;\n')
00237 f.write(' *(outbuffer + offset++) = 0;\n')
00238 f.write(' *(outbuffer + offset++) = 0;\n')
00239 f.write(' for( uint8_t i = 0; i < %s_length; i++){\n' % self.name)
00240 c.serialize(f)
00241 f.write(' }\n')
00242 else:
00243 f.write(' unsigned char * %s_val = (unsigned char *) this->%s;\n' % (self.name, self.name))
00244 f.write(' for( uint8_t i = 0; i < %d; i++){\n' % (self.size) )
00245 c.serialize(f)
00246 f.write(' }\n')
00247
00248 def deserialize(self, f):
00249 if self.size == None:
00250 c = self.cls("st_"+self.name, self.type, self.bytes)
00251
00252 f.write(' uint8_t %s_lengthT = *(inbuffer + offset++);\n' % self.name)
00253 f.write(' if(%s_lengthT > %s_length)\n' % (self.name, self.name))
00254 f.write(' this->%s = (%s*)realloc(this->%s, %s_lengthT * sizeof(%s));\n' % (self.name, self.type, self.name, self.name, self.type))
00255 f.write(' offset += 3;\n')
00256 f.write(' %s_length = %s_lengthT;\n' % (self.name, self.name))
00257
00258 f.write(' for( uint8_t i = 0; i < %s_length; i++){\n' % (self.name) )
00259 c.deserialize(f)
00260 f.write(' memcpy( &(this->%s[i]), &(this->st_%s), sizeof(%s));\n' % (self.name, self.name, self.type))
00261 f.write(' }\n')
00262 else:
00263 c = self.cls(self.name+"[i]", self.type, self.bytes)
00264 f.write(' uint8_t * %s_val = (uint8_t*) this->%s;\n' % (self.name, self.name))
00265 f.write(' for( uint8_t i = 0; i < %d; i++){\n' % (self.size) )
00266 c.deserialize(f)
00267 f.write(' }\n')
00268
00269
00270 ros_to_arduino_types = {
00271 'bool' : ('bool', 1, PrimitiveDataType, []),
00272 'int8' : ('int8_t', 1, PrimitiveDataType, []),
00273 'uint8' : ('uint8_t', 1, PrimitiveDataType, []),
00274 'int16' : ('int16_t', 2, PrimitiveDataType, []),
00275 'uint16' : ('uint16_t', 2, PrimitiveDataType, []),
00276 'int32' : ('int32_t', 4, PrimitiveDataType, []),
00277 'uint32' : ('uint32_t', 4, PrimitiveDataType, []),
00278 'int64' : ('int64_t', 4, PrimitiveDataType, []),
00279 'uint64' : ('uint64_t', 4, PrimitiveDataType, []),
00280 'float32' : ('float', 4, PrimitiveDataType, []),
00281 'float64' : ('float', 4, Float64DataType, []),
00282 'time' : ('ros::Time', 8, TimeDataType, ['ros/time']),
00283 'duration': ('ros::Duration', 8, TimeDataType, ['ros/duration']),
00284 'string' : ('char*', 0, StringDataType, []),
00285 'Header' : ('std_msgs::Header', 0, MessageDataType, ['std_msgs/Header'])
00286 }
00287
00288
00289
00290
00291
00292 class Message:
00293 """ Parses message definitions into something we can export. """
00294
00295 def __init__(self, name, package, definition, md5):
00296
00297 self.name = name
00298 self.package = package
00299 self.md5 = md5
00300 self.includes = list()
00301
00302 self.data = list()
00303 self.enums = list()
00304
00305
00306 for line in definition:
00307
00308 line = line.strip().rstrip()
00309 value = None
00310 if line.find("#") > -1:
00311 line = line[0:line.find("#")]
00312 if line.find("=") > -1:
00313 try:
00314 value = line[line.find("=")+1:]
00315 except:
00316 value = '"' + line[line.find("=")+1:] + '"';
00317 line = line[0:line.find("=")]
00318
00319
00320 line = line.replace("\t", " ")
00321 l = line.split(" ")
00322 while "" in l:
00323 l.remove("")
00324 if len(l) < 2:
00325 continue
00326 ty, name = l[0:2]
00327 if value != None:
00328 self.enums.append( EnumerationType(name, ty, value))
00329 continue
00330
00331 try:
00332 type_package, type_name = ty.split("/")
00333 except:
00334 type_package = None
00335 type_name = ty
00336 type_array = False
00337 if type_name.find('[') > 0:
00338 type_array = True
00339 try:
00340 type_array_size = int(type_name[type_name.find('[')+1:type_name.find(']')])
00341 except:
00342 type_array_size = None
00343 type_name = type_name[0:type_name.find('[')]
00344
00345
00346 try:
00347 code_type = ros_to_arduino_types[type_name][0]
00348 size = ros_to_arduino_types[type_name][1]
00349 cls = ros_to_arduino_types[type_name][2]
00350 for include in ros_to_arduino_types[type_name][3]:
00351 if include not in self.includes:
00352 self.includes.append(include)
00353 except:
00354 if type_package == None:
00355 type_package = self.package
00356 if type_package+"/"+type_name not in self.includes:
00357 self.includes.append(type_package+"/"+type_name)
00358 cls = MessageDataType
00359 code_type = type_package + "::" + type_name
00360 size = 0
00361 if type_array:
00362 self.data.append( ArrayDataType(name, code_type, size, cls, type_array_size ) )
00363 else:
00364 self.data.append( cls(name, code_type, size) )
00365
00366 def _write_serializer(self, f):
00367
00368 f.write('\n')
00369 f.write(' virtual int serialize(unsigned char *outbuffer) const\n')
00370 f.write(' {\n')
00371 f.write(' int offset = 0;\n')
00372 for d in self.data:
00373 d.serialize(f)
00374 f.write(' return offset;\n');
00375 f.write(' }\n')
00376 f.write('\n')
00377
00378 def _write_deserializer(self, f):
00379
00380 f.write(' virtual int deserialize(unsigned char *inbuffer)\n')
00381 f.write(' {\n')
00382 f.write(' int offset = 0;\n')
00383 for d in self.data:
00384 d.deserialize(f)
00385 f.write(' return offset;\n');
00386 f.write(' }\n')
00387 f.write('\n')
00388
00389 def _write_std_includes(self, f):
00390 f.write('#include <stdint.h>\n')
00391 f.write('#include <string.h>\n')
00392 f.write('#include <stdlib.h>\n')
00393 f.write('#include "ros/msg.h"\n')
00394
00395 def _write_msg_includes(self,f):
00396 for i in self.includes:
00397 f.write('#include "%s.h"\n' % i)
00398
00399 def _write_data(self, f):
00400 for d in self.data:
00401 d.make_declaration(f)
00402 for e in self.enums:
00403 e.make_declaration(f)
00404
00405 def _write_getType(self, f):
00406 f.write(' const char * getType(){ return "%s/%s"; };\n'%(self.package, self.name))
00407
00408 def _write_getMD5(self, f):
00409 f.write(' const char * getMD5(){ return "%s"; };\n'%self.md5)
00410
00411 def _write_impl(self, f):
00412 f.write(' class %s : public ros::Msg\n' % self.name)
00413 f.write(' {\n')
00414 f.write(' public:\n')
00415 self._write_data(f)
00416 self._write_serializer(f)
00417 self._write_deserializer(f)
00418 self._write_getType(f)
00419 self._write_getMD5(f)
00420 f.write('\n')
00421 f.write(' };\n')
00422
00423 def make_header(self, f):
00424 f.write('#ifndef _ROS_%s_%s_h\n'%(self.package, self.name))
00425 f.write('#define _ROS_%s_%s_h\n'%(self.package, self.name))
00426 f.write('\n')
00427 self._write_std_includes(f)
00428 self._write_msg_includes(f)
00429
00430 f.write('\n')
00431 f.write('namespace %s\n' % self.package)
00432 f.write('{\n')
00433 f.write('\n')
00434 self._write_impl(f)
00435 f.write('\n')
00436 f.write('}\n')
00437
00438 f.write('#endif')
00439
00440 class Service:
00441 def __init__(self, name, package, definition, md5req, md5res):
00442 """
00443 @param name - name of service
00444 @param package - name of service package
00445 @param definition - list of lines of definition
00446 """
00447
00448 self.name = name
00449 self.package = package
00450
00451 sep_line = None
00452 sep = re.compile('---*')
00453 for i in range(0, len(definition)):
00454 if (None!= re.match(sep, definition[i]) ):
00455 sep_line = i
00456 break
00457 self.req_def = definition[0:sep_line]
00458 self.resp_def = definition[sep_line+1:]
00459
00460 self.req = Message(name+"Request", package, self.req_def, md5req)
00461 self.resp = Message(name+"Response", package, self.resp_def, md5res)
00462
00463 def make_header(self, f):
00464 f.write('#ifndef _ROS_SERVICE_%s_h\n' % self.name)
00465 f.write('#define _ROS_SERVICE_%s_h\n' % self.name)
00466
00467 self.req._write_std_includes(f)
00468 includes = self.req.includes
00469 includes.extend(self.resp.includes)
00470 includes = list(set(includes))
00471 for inc in includes:
00472 f.write('#include "%s.h"\n' % inc)
00473
00474 f.write('\n')
00475 f.write('namespace %s\n' % self.package)
00476 f.write('{\n')
00477 f.write('\n')
00478 f.write('static const char %s[] = "%s/%s";\n'%(self.name.upper(), self.package, self.name))
00479
00480 def write_type(out, name):
00481 out.write(' const char * getType(){ return %s; };\n'%(name))
00482 _write_getType = lambda out: write_type(out, self.name.upper())
00483 self.req._write_getType = _write_getType
00484 self.resp._write_getType = _write_getType
00485
00486 f.write('\n')
00487 self.req._write_impl(f)
00488 f.write('\n')
00489 self.resp._write_impl(f)
00490 f.write('\n')
00491 f.write(' class %s {\n' % self.name )
00492 f.write(' public:\n')
00493 f.write(' typedef %s Request;\n' % self.req.name )
00494 f.write(' typedef %s Response;\n' % self.resp.name )
00495 f.write(' };\n')
00496 f.write('\n')
00497
00498 f.write('}\n')
00499
00500 f.write('#endif')
00501
00502
00503
00504
00505
00506
00507 def MakeLibrary(package, output_path):
00508 print "Exporting " + package + "\n",
00509
00510 pkg_dir = roslib.packages.get_pkg_dir(package)
00511
00512 sys.stdout.write(' Messages:')
00513
00514 messages = list()
00515 if os.path.exists(pkg_dir+"/msg"):
00516 sys.stdout.write('\n ')
00517 for f in os.listdir(pkg_dir+"/msg"):
00518 if f.endswith(".msg"):
00519 file = pkg_dir + "/msg/" + f
00520
00521 print "%s," % f[0:-4],
00522 definition = open(file).readlines()
00523 md5sum = roslib.gentools.compute_md5(roslib.gentools.get_file_dependencies(file))
00524 messages.append( Message(f[0:-4], package, definition, md5sum) )
00525 print "\n"
00526
00527 sys.stdout.write(' Services:')
00528
00529 services = list()
00530 if (os.path.exists(pkg_dir+"/srv/")):
00531 sys.stdout.write('\n ')
00532 for f in os.listdir(pkg_dir+"/srv"):
00533 if f.endswith(".srv"):
00534 file = pkg_dir + "/srv/" + f
00535
00536 print "%s," % f[0:-4],
00537 definition, service = roslib.srvs.load_from_file(file)
00538 definition = open(file).readlines()
00539 md5req = roslib.gentools.compute_md5(roslib.gentools.get_dependencies(service.request, package))
00540 md5res = roslib.gentools.compute_md5(roslib.gentools.get_dependencies(service.response, package))
00541 messages.append( Service(f[0:-4], package, definition, md5req, md5res ) )
00542 print "\n"
00543
00544
00545 output_path = output_path + "/" + package
00546 for msg in messages:
00547 if not os.path.exists(output_path):
00548 os.makedirs(output_path)
00549 header = open(output_path + "/" + msg.name + ".h", "w")
00550 msg.make_header(header)
00551 header.close()
00552
00553
00554 def add_depends(packages, package):
00555 depend = [package] + roslib.rospack.rospack_depends(package)
00556 for p in depend:
00557 if not p in packages:
00558 packages.append(p)
00559 packages = add_depends(packages, p)
00560 return packages
00561
00562 if __name__=="__main__":
00563
00564
00565 if (len(sys.argv) <3):
00566 print __usage__
00567 exit()
00568
00569
00570 path = sys.argv[1]
00571 if path[-1] == "/":
00572 path = path[0:-1]
00573 path += "/ros_lib"
00574 print "\nExporting to %s" % path
00575
00576 packages = list()
00577
00578 for package in sys.argv[2:]:
00579 packages = add_depends(packages, package)
00580
00581 print packages
00582 for package in packages:
00583 MakeLibrary(package, path)
00584