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