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