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