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