$search
00001 #!/usr/bin/env python 00002 # Software License Agreement (BSD License) 00003 # 00004 # Copyright (c) 2009, Willow Garage, Inc. 00005 # All rights reserved. 00006 # 00007 # Redistribution and use in source and binary forms, with or without 00008 # modification, are permitted provided that the following conditions 00009 # are met: 00010 # 00011 # * Redistributions of source code must retain the above copyright 00012 # notice, this list of conditions and the following disclaimer. 00013 # * Redistributions in binary form must reproduce the above 00014 # copyright notice, this list of conditions and the following 00015 # disclaimer in the documentation and/or other materials provided 00016 # with the distribution. 00017 # * Neither the name of Willow Garage, Inc. nor the names of its 00018 # contributors may be used to endorse or promote products derived 00019 # from this software without specific prior written permission. 00020 # 00021 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 # POSSIBILITY OF SUCH DAMAGE. 00033 # 00034 00035 ## ROS message source code generation for Lisp 00036 ## 00037 ## Converts ROS .msg and .srv files in a package into Lisp source code 00038 00039 ## t0: needed for script to work 00040 ## t1: for reference; remove once running 00041 ## t2: can be changed once we remove strict diff-compatibility requirement with old version of genmsg_lisp 00042 00043 from __future__ import with_statement 00044 00045 import roslib; roslib.load_manifest('roslisp') 00046 00047 import sys 00048 import os 00049 import traceback 00050 import re 00051 00052 import roslib.msgs 00053 import roslib.srvs 00054 import roslib.packages 00055 import roslib.gentools 00056 from roslib.msgs import MsgSpec 00057 from roslib.srvs import SrvSpec 00058 00059 try: 00060 from cStringIO import StringIO #Python 2.x 00061 except ImportError: 00062 from io import StringIO #Python 3.x 00063 00064 ############################################################ 00065 # Built in types 00066 ############################################################ 00067 00068 def is_fixnum(t): 00069 return t in ['int8', 'uint8', 'int16', 'uint16'] 00070 00071 def is_integer(t): 00072 return is_fixnum(t) or t in ['byte', 'char', 'int32', 'uint32', 'int64', 'uint64'] #t2 byte, char can be fixnum 00073 00074 def is_signed_int(t): 00075 return t in ['int8', 'int16', 'int32', 'int64'] 00076 00077 def is_unsigned_int(t): 00078 return t in ['uint8', 'uint16', 'uint32', 'uint64'] 00079 00080 def is_bool(t): 00081 return t == 'bool' 00082 00083 def is_string(t): 00084 return t == 'string' 00085 00086 def is_float(t): 00087 return t in ['float16', 'float32', 'float64'] 00088 00089 def is_time(t): 00090 return t in ['time', 'duration'] 00091 00092 def field_type(f): 00093 if f.is_builtin: 00094 elt_type = lisp_type(f.base_type) 00095 else: 00096 elt_type = msg_type(f) 00097 if f.is_array: 00098 return '(cl:vector %s)'%elt_type 00099 else: 00100 return elt_type 00101 00102 def parse_msg_type(f): 00103 if f.base_type == 'Header': 00104 return ('std_msgs', 'Header') 00105 else: 00106 return f.base_type.split('/') 00107 00108 # t2 no need for is_array 00109 def msg_type(f): 00110 (pkg, msg) = parse_msg_type(f) 00111 return '%s-msg:%s'%(pkg, msg) 00112 00113 def lisp_type(t): 00114 if is_fixnum(t): 00115 return 'cl:fixnum' 00116 elif is_integer(t): 00117 return 'cl:integer' 00118 elif is_bool(t): 00119 return 'cl:boolean' 00120 elif is_float(t): 00121 return 'cl:float' 00122 elif is_time(t): 00123 return 'cl:real' 00124 elif is_string(t): 00125 return 'cl:string' 00126 else: 00127 raise ValueError('%s is not a recognized primitive type'%t) 00128 00129 def field_initform(f): 00130 if f.is_builtin: 00131 initform = lisp_initform(f.base_type) 00132 elt_type = lisp_type(f.base_type) 00133 else: 00134 initform = '(cl:make-instance \'%s)'%msg_type(f) 00135 elt_type = msg_type(f) 00136 if f.is_array: 00137 len = f.array_len or 0 00138 return '(cl:make-array %s :element-type \'%s :initial-element %s)'%(len, elt_type, initform) 00139 else: 00140 return initform 00141 00142 def lisp_initform(t): 00143 if is_integer(t): 00144 return '0' 00145 elif is_bool(t): 00146 return 'cl:nil' 00147 elif is_float(t): 00148 return '0.0' 00149 elif is_time(t): 00150 return 0 00151 elif is_string(t): 00152 return '\"\"' 00153 else: 00154 raise ValueError('%s is not a recognized primitive type'%t) 00155 00156 NUM_BYTES = {'int8': 1, 'int16': 2, 'int32': 4, 'int64': 8, 00157 'uint8': 1, 'uint16': 2, 'uint32': 4, 'uint64': 8} 00158 00159 00160 00161 ############################################################ 00162 # Indented writer 00163 ############################################################ 00164 00165 class IndentedWriter(): 00166 00167 def __init__(self, s): 00168 self.str = s 00169 self.indentation = 0 00170 self.block_indent = False 00171 00172 def write(self, s, indent=True, newline=True): 00173 if not indent: 00174 newline = False 00175 if self.block_indent: 00176 self.block_indent = False 00177 else: 00178 if newline: 00179 self.str.write('\n') 00180 if indent: 00181 for i in range(self.indentation): 00182 self.str.write(' ') 00183 self.str.write(s) 00184 00185 def newline(self): 00186 self.str.write('\n') 00187 00188 def inc_indent(self, inc=2): 00189 self.indentation += inc 00190 00191 def dec_indent(self, dec=2): 00192 self.indentation -= dec 00193 00194 def reset_indent(self): 00195 self.indentation = 0 00196 00197 def block_next_indent(self): 00198 self.block_indent = True 00199 00200 class Indent(): 00201 00202 def __init__(self, w, inc=2, indent_first=True): 00203 self.writer = w 00204 self.inc = inc 00205 self.indent_first = indent_first 00206 00207 def __enter__(self): 00208 self.writer.inc_indent(self.inc) 00209 if not self.indent_first: 00210 self.writer.block_next_indent() 00211 00212 def __exit__(self, type, val, traceback): 00213 self.writer.dec_indent(self.inc) 00214 00215 00216 00217 def write_begin(s, spec, path, is_service=False): 00218 "Writes the beginning of the file: a comment saying it's auto-generated and the in-package form" 00219 00220 s.write('; Auto-generated. Do not edit!\n\n\n', newline=False) 00221 suffix = 'srv' if is_service else 'msg' 00222 s.write('(cl:in-package %s-%s)\n\n\n'%(spec.package, suffix), newline=False) 00223 00224 def write_html_include(s, spec, is_srv=False): 00225 00226 s.write(';//! \\htmlinclude %s.msg.html\n'%spec.actual_name, newline=False) # t2 00227 00228 def write_slot_definition(s, field): 00229 "Write the definition of a slot corresponding to a single message field" 00230 00231 s.write('(%s'%field.name) 00232 with Indent(s, 1): 00233 s.write(':reader %s'%field.name) 00234 s.write(':initarg :%s'%field.name) 00235 s.write(':type %s'%field_type(field)) 00236 i = 0 if field.is_array else 1 # t2 00237 with Indent(s, i): 00238 s.write(':initform %s)'%field_initform(field)) 00239 00240 def write_deprecated_readers(s, spec): 00241 suffix = 'srv' if spec.component_type == 'service' else 'msg' 00242 for field in spec.parsed_fields(): 00243 s.newline() 00244 s.write('(cl:ensure-generic-function \'%s-val :lambda-list \'(m))' % field.name) 00245 s.write('(cl:defmethod %s-val ((m %s))'%(field.name, message_class(spec))) 00246 with Indent(s): 00247 s.write('(roslisp-msg-protocol:msg-deprecation-warning "Using old-style slot reader %s-%s:%s-val is deprecated. Use %s-%s:%s instead.")'%(spec.package, suffix, field.name, spec.package, suffix, field.name)) 00248 s.write('(%s m))'%field.name) 00249 00250 00251 00252 def write_defclass(s, spec): 00253 "Writes the defclass that defines the message type" 00254 cl = message_class(spec) 00255 new_cl = new_message_class(spec) 00256 suffix = 'srv' if spec.component_type == 'service' else 'msg' 00257 s.write('(cl:defclass %s (roslisp-msg-protocol:ros-message)'%cl) 00258 with Indent(s): 00259 s.write('(') 00260 with Indent(s, inc=1, indent_first=False): 00261 for field in spec.parsed_fields(): 00262 write_slot_definition(s, field) 00263 s.write(')', indent=False) 00264 s.write(')') 00265 s.newline() 00266 s.write('(cl:defclass %s (%s)'%(new_cl, cl)) 00267 with Indent(s): 00268 s.write('())') 00269 s.newline() 00270 s.write('(cl:defmethod cl:initialize-instance :after ((m %s) cl:&rest args)'%cl) 00271 with Indent(s): 00272 s.write('(cl:declare (cl:ignorable args))') 00273 s.write('(cl:unless (cl:typep m \'%s)'%new_cl) 00274 with Indent(s): 00275 s.write('(roslisp-msg-protocol:msg-deprecation-warning "using old message class name %s-%s:%s is deprecated: use %s-%s:%s instead.")))'%(spec.package, suffix, cl, spec.package, suffix, new_cl)) 00276 00277 00278 00279 def message_class(spec): 00280 """ 00281 Return the CLOS class name for this message type 00282 """ 00283 return '<%s>'%spec.actual_name 00284 00285 def new_message_class(spec): 00286 return spec.actual_name 00287 00288 00289 def write_serialize_length(s, v, is_array=False): 00290 #t2 00291 var = '__ros_arr_len' if is_array else '__ros_str_len' 00292 00293 s.write('(cl:let ((%s (cl:length %s)))'%(var, v)) 00294 with Indent(s): 00295 for x in range(0, 32, 8): 00296 s.write('(cl:write-byte (cl:ldb (cl:byte 8 %s) %s) ostream)'%(x, var)) 00297 s.write(')', indent=False) 00298 00299 00300 def write_serialize_bits(s, v, num_bytes): 00301 for x in range(0, num_bytes*8, 8): 00302 s.write('(cl:write-byte (cl:ldb (cl:byte 8 %s) %s) ostream)'%(x, v)) 00303 00304 def write_serialize_bits_signed(s, v, num_bytes): 00305 num_bits = num_bytes*8 00306 s.write('(cl:let* ((signed %s) (unsigned (cl:if (cl:< signed 0) (cl:+ signed %s) signed)))'%(v, 2**num_bits)) 00307 with Indent(s): 00308 write_serialize_bits(s, 'unsigned', num_bytes) 00309 s.write(')') 00310 00311 00312 00313 # t2: can get rid of this lookup_slot stuff 00314 def write_serialize_builtin(s, f, var='msg', lookup_slot=True): 00315 v = '(cl:slot-value %s \'%s)'%(var, f.name) if lookup_slot else var 00316 if f.base_type == 'string': 00317 write_serialize_length(s, v) 00318 s.write('(cl:map cl:nil #\'(cl:lambda (c) (cl:write-byte (cl:char-code c) ostream)) %s)'%v) 00319 elif f.base_type == 'float32': 00320 s.write('(cl:let ((bits %s))'%'(roslisp-utils:encode-single-float-bits %s)'%v) 00321 with Indent(s): 00322 write_serialize_bits(s, 'bits', 4) 00323 s.write(')', False) 00324 elif f.base_type == 'float64': 00325 s.write('(cl:let ((bits %s))'%'(roslisp-utils:encode-double-float-bits %s)'%v) 00326 with Indent(s): 00327 write_serialize_bits(s, 'bits', 8) 00328 s.write(')', False) 00329 elif f.base_type == 'bool': 00330 s.write('(cl:write-byte (cl:ldb (cl:byte 8 0) (cl:if %s 1 0)) ostream)'%v) 00331 elif f.base_type in ['byte', 'char']: 00332 s.write('(cl:write-byte (cl:ldb (cl:byte 8 0) %s) ostream)'%v) 00333 elif f.base_type in ['duration', 'time']: 00334 s.write('(cl:let ((__sec (cl:floor %s))'%v) 00335 s.write(' (__nsec (cl:round (cl:* 1e9 (cl:- %s (cl:floor %s))))))'%(v,v)) 00336 with Indent(s): 00337 write_serialize_bits(s, '__sec', 4) 00338 write_serialize_bits(s, '__nsec', 4) 00339 s.write(')', False) 00340 elif is_signed_int(f.base_type): 00341 write_serialize_bits_signed(s, v, NUM_BYTES[f.base_type]) 00342 elif is_unsigned_int(f.base_type): 00343 write_serialize_bits(s, v, NUM_BYTES[f.base_type]) 00344 else: 00345 raise ValueError('Unknown type: %s', f.base_type) 00346 00347 def write_serialize_field(s, f): 00348 slot = '(cl:slot-value msg \'%s)'%f.name 00349 if f.is_array: 00350 if not f.array_len: 00351 write_serialize_length(s, slot, True) 00352 s.write('(cl:map cl:nil #\'(cl:lambda (ele) ') 00353 var = 'ele' 00354 s.block_next_indent() 00355 lookup_slot = False 00356 else: 00357 var='msg' 00358 lookup_slot = True 00359 00360 if f.is_builtin: 00361 write_serialize_builtin(s, f, var, lookup_slot=lookup_slot) 00362 else: 00363 to_write = slot if lookup_slot else var #t2 00364 s.write('(roslisp-msg-protocol:serialize %s ostream)'%to_write) 00365 00366 if f.is_array: 00367 s.write(')', False) 00368 s.write(' %s)'%slot) 00369 00370 def write_serialize(s, spec): 00371 """ 00372 Write the serialize method 00373 """ 00374 s.write('(cl:defmethod roslisp-msg-protocol:serialize ((msg %s) ostream)'%message_class(spec)) 00375 with Indent(s): 00376 s.write('"Serializes a message object of type \'%s"'%message_class(spec)) 00377 for f in spec.parsed_fields(): 00378 write_serialize_field(s, f) 00379 s.write(')') 00380 00381 00382 # t2 can get rid of is_array 00383 def write_deserialize_length(s, is_array=False): 00384 var = '__ros_arr_len' if is_array else '__ros_str_len' 00385 s.write('(cl:let ((%s 0))'%var) 00386 with Indent(s): 00387 for x in range(0, 32, 8): 00388 s.write('(cl:setf (cl:ldb (cl:byte 8 %s) %s) (cl:read-byte istream))'%(x, var)) 00389 00390 def write_deserialize_bits(s, v, num_bytes): 00391 for x in range(0, num_bytes*8, 8): 00392 s.write('(cl:setf (cl:ldb (cl:byte 8 %s) %s) (cl:read-byte istream))'%(x, v)) 00393 00394 def write_deserialize_bits_signed(s, v, num_bytes): 00395 s.write('(cl:let ((unsigned 0))') 00396 num_bits = 8*num_bytes 00397 with Indent(s): 00398 write_deserialize_bits(s, 'unsigned', num_bytes) 00399 s.write('(cl:setf %s (cl:if (cl:< unsigned %s) unsigned (cl:- unsigned %s))))'%(v, 2**(num_bits-1), 2**num_bits)) 00400 00401 00402 00403 def write_deserialize_builtin(s, f, v): 00404 if f.base_type == 'string': 00405 write_deserialize_length(s) 00406 with Indent(s): 00407 s.write('(cl:setf %s (cl:make-string __ros_str_len))'%v) 00408 s.write('(cl:dotimes (__ros_str_idx __ros_str_len msg)') 00409 with Indent(s): 00410 s.write('(cl:setf (cl:char %s __ros_str_idx) (cl:code-char (cl:read-byte istream)))))'%v) 00411 elif f.base_type == 'float32': 00412 s.write('(cl:let ((bits 0))') 00413 with Indent(s): 00414 write_deserialize_bits(s, 'bits', 4) 00415 s.write('(cl:setf %s (roslisp-utils:decode-single-float-bits bits)))'%v) 00416 elif f.base_type == 'float64': 00417 s.write('(cl:let ((bits 0))') 00418 with Indent(s): 00419 write_deserialize_bits(s, 'bits', 8) 00420 s.write('(cl:setf %s (roslisp-utils:decode-double-float-bits bits)))'%v) 00421 elif f.base_type == 'bool': 00422 s.write('(cl:setf %s (cl:not (cl:zerop (cl:read-byte istream))))'%v) 00423 elif f.base_type in ['byte', 'char']: 00424 s.write('(cl:setf (cl:ldb (cl:byte 8 0) %s) (cl:read-byte istream))'%v) 00425 elif f.base_type in ['duration', 'time']: 00426 s.write('(cl:let ((__sec 0) (__nsec 0))') 00427 with Indent(s): 00428 write_deserialize_bits(s, '__sec', 4) 00429 write_deserialize_bits(s, '__nsec', 4) 00430 s.write('(cl:setf %s (cl:+ (cl:coerce __sec \'cl:double-float) (cl:/ __nsec 1e9))))'%v) 00431 elif is_signed_int(f.base_type): 00432 write_deserialize_bits_signed(s, v, NUM_BYTES[f.base_type]) 00433 elif is_unsigned_int(f.base_type): 00434 write_deserialize_bits(s, v, NUM_BYTES[f.base_type]) 00435 else: 00436 raise ValueError('%s unknown'%f.base_type) 00437 00438 00439 def write_deserialize_field(s, f, pkg): 00440 slot = '(cl:slot-value msg \'%s)'%f.name 00441 var = slot 00442 if f.is_array: 00443 if not f.array_len: 00444 write_deserialize_length(s, True) 00445 length = '__ros_arr_len' 00446 else: 00447 length = '%s'%f.array_len 00448 00449 s.write('(cl:setf %s (cl:make-array %s))'%(slot, length)) 00450 s.write('(cl:let ((vals %s))'%slot) # t2 00451 var = '(cl:aref vals i)' 00452 with Indent(s): 00453 s.write('(cl:dotimes (i %s)'%length) 00454 00455 if f.is_builtin: 00456 with Indent(s): 00457 write_deserialize_builtin(s, f, var) 00458 else: 00459 if f.is_array: 00460 with Indent(s): 00461 s.write('(cl:setf %s (cl:make-instance \'%s))'%(var, msg_type(f))) 00462 s.write('(roslisp-msg-protocol:deserialize %s istream)'%var) 00463 00464 if f.is_array: 00465 s.write('))', False) 00466 if not f.array_len: 00467 s.write(')', False) 00468 00469 00470 def write_deserialize(s, spec): 00471 """ 00472 Write the deserialize method 00473 """ 00474 s.write('(cl:defmethod roslisp-msg-protocol:deserialize ((msg %s) istream)'%message_class(spec)) 00475 with Indent(s): 00476 s.write('"Deserializes a message object of type \'%s"'%message_class(spec)) 00477 for f in spec.parsed_fields(): 00478 write_deserialize_field(s, f, spec.package) 00479 s.write('msg') 00480 s.write(')') 00481 00482 def write_class_exports(s, pkg): 00483 "Write the _package.lisp file" 00484 s.write('(cl:defpackage %s-msg'%pkg, False) 00485 with Indent(s): 00486 s.write('(:use )') 00487 s.write('(:export') 00488 with Indent(s, inc=1): 00489 for spec in roslib.msgs.get_pkg_msg_specs(pkg)[0]: 00490 (p, msg_type) = spec[0].split('/') 00491 msg_class = '<%s>'%msg_type 00492 s.write('"%s"'%msg_class.upper()) 00493 s.write('"%s"'%msg_type.upper()) 00494 s.write('))\n\n') 00495 00496 def write_srv_exports(s, pkg): 00497 "Write the _package.lisp file for a service directory" 00498 s.write('(cl:defpackage %s-srv'%pkg, False) 00499 with Indent(s): 00500 s.write('(:use )') 00501 s.write('(:export') 00502 with Indent(s, inc=1): 00503 for spec in roslib.srvs.get_pkg_srv_specs(pkg)[0]: 00504 (_, srv_type) = spec[0].split('/') 00505 s.write('"%s"'%srv_type.upper()) 00506 s.write('"<%s-REQUEST>"'%srv_type.upper()) 00507 s.write('"%s-REQUEST"'%srv_type.upper()) 00508 s.write('"<%s-RESPONSE>"'%srv_type.upper()) 00509 s.write('"%s-RESPONSE"'%srv_type.upper()) 00510 s.write('))\n\n') 00511 00512 00513 def write_asd_deps(s, deps, msgs): 00514 with Indent(s): 00515 s.write(':depends-on (:roslisp-msg-protocol :roslisp-utils ') 00516 with Indent(s, inc=13, indent_first=False): 00517 for d in sorted(deps): 00518 s.write(':%s-msg'%d) 00519 s.write(')') #t2 indentation 00520 with Indent(s): 00521 s.write(':components ((:file "_package")') 00522 with Indent(s): 00523 for (full_name, _) in msgs: 00524 (_, name) = full_name.split('/') 00525 s.write('(:file "%s" :depends-on ("_package_%s"))'%(name, name)) 00526 s.write('(:file "_package_%s" :depends-on ("_package"))'%name) 00527 s.write('))') 00528 00529 00530 00531 def write_srv_asd(s, pkg): 00532 s.write('(cl:in-package :asdf)') 00533 s.newline() 00534 s.write('(defsystem "%s-srv"'%pkg) 00535 services = roslib.srvs.get_pkg_srv_specs(pkg)[0] 00536 00537 # Figure out set of depended-upon ros packages 00538 deps = set() 00539 for (_, spec) in services: 00540 for f in spec.request.parsed_fields(): 00541 if not f.is_builtin: 00542 (p, _) = parse_msg_type(f) 00543 deps.add(p) 00544 for f in spec.response.parsed_fields(): 00545 if not f.is_builtin: 00546 (p, _) = parse_msg_type(f) 00547 deps.add(p) 00548 00549 write_asd_deps(s, deps, services) 00550 00551 00552 def write_asd(s, pkg): 00553 s.write('(cl:in-package :asdf)') 00554 s.newline() 00555 s.write('(defsystem "%s-msg"'%pkg) 00556 msgs = roslib.msgs.get_pkg_msg_specs(pkg)[0] 00557 00558 # Figure out set of depended-upon ros packages 00559 deps = set() 00560 for (_, spec) in msgs: 00561 for f in spec.parsed_fields(): 00562 if not f.is_builtin: 00563 (p, _) = parse_msg_type(f) 00564 deps.add(p) 00565 if pkg in deps: 00566 deps.remove(pkg) 00567 write_asd_deps(s, deps, msgs) 00568 00569 def write_accessor_exports(s, spec): 00570 "Write the package exports for this message/service" 00571 is_srv = isinstance(spec, SrvSpec) 00572 suffix = 'srv' if is_srv else 'msg' 00573 s.write('(cl:in-package %s-%s)'%(spec.package, suffix), indent=False) 00574 s.write('(cl:export \'(') 00575 if is_srv: 00576 fields = spec.request.parsed_fields()[:] 00577 fields.extend(spec.response.parsed_fields()) 00578 else: 00579 fields = spec.parsed_fields() 00580 00581 with Indent(s, inc=10, indent_first=False): 00582 for f in fields: 00583 accessor = '%s-val'%f.name 00584 s.write('%s'%accessor.upper()) 00585 s.write('%s'%f.name.upper()) 00586 s.write('))') 00587 00588 00589 def write_ros_datatype(s, spec): 00590 for c in (message_class(spec), new_message_class(spec)): 00591 s.write('(cl:defmethod roslisp-msg-protocol:ros-datatype ((msg (cl:eql \'%s)))'%c) 00592 with Indent(s): 00593 s.write('"Returns string type for a %s object of type \'%s"'%(spec.component_type, c)) 00594 s.write('"%s")'%spec.full_name) 00595 00596 def write_md5sum(s, spec, parent=None): 00597 if parent is None: 00598 parent = spec 00599 gendeps_dict = roslib.gentools.get_dependencies(parent, spec.package, 00600 compute_files=False) 00601 md5sum = roslib.gentools.compute_md5(gendeps_dict) 00602 for c in (message_class(spec), new_message_class(spec)): 00603 s.write('(cl:defmethod roslisp-msg-protocol:md5sum ((type (cl:eql \'%s)))'%c) 00604 with Indent(s): 00605 # t2 this should print 'service' instead of 'message' if it's a service request or response 00606 s.write('"Returns md5sum for a message object of type \'%s"'%c) 00607 s.write('"%s")'%md5sum) 00608 00609 def write_message_definition(s, spec): 00610 for c in (message_class(spec), new_message_class(spec)): 00611 s.write('(cl:defmethod roslisp-msg-protocol:message-definition ((type (cl:eql \'%s)))'%c) 00612 with Indent(s): 00613 s.write('"Returns full string definition for message of type \'%s"'%c) 00614 s.write('(cl:format cl:nil "') 00615 gendeps_dict = roslib.gentools.get_dependencies(spec, spec.package, compute_files=False) 00616 definition = roslib.gentools.compute_full_text(gendeps_dict) 00617 lines = definition.split('\n') 00618 for line in lines: 00619 l = line.replace('\\', '\\\\') 00620 l = l.replace('"', '\\"') 00621 s.write('%s~%%'%l, indent=False) 00622 s.write('~%', indent=False) 00623 s.write('"))', indent=False) 00624 00625 def write_builtin_length(s, f, var='msg'): 00626 if f.base_type in ['int8', 'uint8']: 00627 s.write('1') 00628 elif f.base_type in ['int16', 'uint16']: 00629 s.write('2') 00630 elif f.base_type in ['int32', 'uint32', 'float32']: 00631 s.write('4') 00632 elif f.base_type in ['int64', 'uint64', 'float64', 'duration', 'time']: 00633 s.write('8') 00634 elif f.base_type == 'string': 00635 s.write('4 (cl:length %s)'%var) 00636 elif f.base_type in ['bool', 'byte', 'char']: 00637 s.write('1') 00638 else: 00639 raise ValueError('Unknown: %s', f.base_type) 00640 00641 def write_serialization_length(s, spec): 00642 c = message_class(spec) 00643 s.write('(cl:defmethod roslisp-msg-protocol:serialization-length ((msg %s))'%c) 00644 with Indent(s): 00645 s.write('(cl:+ 0') 00646 with Indent(s, 3): 00647 for field in spec.parsed_fields(): 00648 slot = '(cl:slot-value msg \'%s)'%field.name 00649 if field.is_array: 00650 l = '0' if field.array_len else '4' 00651 s.write('%s (cl:reduce #\'cl:+ %s :key #\'(cl:lambda (ele) (cl:declare (cl:ignorable ele)) (cl:+ '%(l, slot)) 00652 var = 'ele' 00653 s.block_next_indent() 00654 else: 00655 var = slot 00656 00657 if field.is_builtin: 00658 write_builtin_length(s, field, var) 00659 else: 00660 s.write('(roslisp-msg-protocol:serialization-length %s)'%var) 00661 00662 if field.is_array: 00663 s.write(')))', False) 00664 s.write('))') 00665 00666 00667 def write_list_converter(s, spec): 00668 c = message_class(spec) 00669 s.write('(cl:defmethod roslisp-msg-protocol:ros-message-to-list ((msg %s))'%c) 00670 with Indent(s): 00671 s.write('"Converts a ROS message object to a list"') 00672 s.write('(cl:list \'%s'%new_message_class(spec)) 00673 with Indent(s): 00674 for f in spec.parsed_fields(): 00675 s.write('(cl:cons \':%s (%s msg))'%(f.name, f.name)) 00676 s.write('))') 00677 00678 def write_constants(s, spec): 00679 if spec.constants: 00680 for cls in (message_class(spec), new_message_class(spec)): 00681 s.write('(cl:defmethod roslisp-msg-protocol:symbol-codes ((msg-type (cl:eql \'%s)))'%cls) 00682 with Indent(s): 00683 s.write(' "Constants for message type \'%s"'%cls) 00684 s.write('\'(') 00685 with Indent(s, indent_first=False): 00686 for c in spec.constants: 00687 s.write('(:%s . %s)'%(c.name.upper(), c.val)) 00688 s.write(')', False) 00689 s.write(')') 00690 00691 00692 def write_srv_component(s, spec, parent): 00693 spec.component_type='service' 00694 write_html_include(s, spec) 00695 write_defclass(s, spec) 00696 write_deprecated_readers(s, spec) 00697 write_constants(s, spec) 00698 write_serialize(s, spec) 00699 write_deserialize(s, spec) 00700 write_ros_datatype(s, spec) 00701 write_md5sum(s, spec, parent) 00702 write_message_definition(s, spec) 00703 write_serialization_length(s, spec) 00704 write_list_converter(s, spec) 00705 00706 00707 def write_service_specific_methods(s, spec): 00708 spec.actual_name=spec.short_name 00709 s.write('(cl:defmethod roslisp-msg-protocol:service-request-type ((msg (cl:eql \'%s)))'%spec.short_name) 00710 with Indent(s): 00711 s.write('\'%s)'%new_message_class(spec.request)) 00712 s.write('(cl:defmethod roslisp-msg-protocol:service-response-type ((msg (cl:eql \'%s)))'%spec.short_name) 00713 with Indent(s): 00714 s.write('\'%s)'%new_message_class(spec.response)) 00715 s.write('(cl:defmethod roslisp-msg-protocol:ros-datatype ((msg (cl:eql \'%s)))'%spec.short_name) 00716 with Indent(s): 00717 s.write('"Returns string type for a service object of type \'%s"'%message_class(spec)) 00718 s.write('"%s")'%spec.full_name) 00719 00720 00721 def generate_msg(msg_path): 00722 """ 00723 Generate a message 00724 00725 @param msg_path: The path to the .msg file 00726 @type msg_path: str 00727 """ 00728 (package_dir, package) = roslib.packages.get_dir_pkg(msg_path) 00729 (_, spec) = roslib.msgs.load_from_file(msg_path, package) 00730 spec.actual_name=spec.short_name 00731 spec.component_type='message' 00732 00733 ######################################## 00734 # 1. Write the .lisp file 00735 ######################################## 00736 00737 io = StringIO() 00738 s = IndentedWriter(io) 00739 write_begin(s, spec, msg_path) 00740 write_html_include(s, spec) 00741 write_defclass(s, spec) 00742 write_deprecated_readers(s, spec) 00743 write_constants(s, spec) 00744 write_serialize(s, spec) 00745 write_deserialize(s, spec) 00746 write_ros_datatype(s, spec) 00747 write_md5sum(s, spec) 00748 write_message_definition(s, spec) 00749 write_serialization_length(s, spec) 00750 write_list_converter(s, spec) 00751 00752 output_dir = '%s/msg_gen/lisp'%package_dir 00753 if (not os.path.exists(output_dir)): 00754 # if we're being run concurrently, the above test can report false but os.makedirs can still fail if 00755 # another copy just created the directory 00756 try: 00757 os.makedirs(output_dir) 00758 except OSError as e: 00759 pass 00760 00761 with open('%s/%s.lisp'%(output_dir, spec.short_name), 'w') as f: 00762 f.write(io.getvalue() + "\n") 00763 io.close() 00764 00765 ######################################## 00766 # 2. Write the _package file 00767 # for this message 00768 ######################################## 00769 00770 io = StringIO() 00771 s = IndentedWriter(io) 00772 write_accessor_exports(s, spec) 00773 with open('%s/_package_%s.lisp'%(output_dir, spec.short_name), 'w') as f: 00774 f.write(io.getvalue()) 00775 io.close() 00776 00777 ######################################## 00778 # 3. Write the _package.lisp file 00779 # This is being rewritten once per msg 00780 # file, which is inefficient 00781 ######################################## 00782 00783 io = StringIO() 00784 s = IndentedWriter(io) 00785 write_class_exports(s, package) 00786 with open('%s/_package.lisp'%output_dir, 'w') as f: 00787 f.write(io.getvalue()) 00788 io.close() 00789 00790 ######################################## 00791 # 4. Write the .asd file 00792 # This is being written once per msg 00793 # file, which is inefficient 00794 ######################################## 00795 00796 io = StringIO() 00797 s = IndentedWriter(io) 00798 write_asd(s, package) 00799 with open('%s/%s-msg.asd'%(output_dir, package), 'w') as f: 00800 f.write(io.getvalue()) 00801 io.close() 00802 00803 # t0 most of this could probably be refactored into being shared with messages 00804 def generate_srv(srv_path): 00805 "Generate code from .srv file" 00806 (pkg_dir, pkg) = roslib.packages.get_dir_pkg(srv_path) 00807 (_, spec) = roslib.srvs.load_from_file(srv_path, pkg) 00808 output_dir = '%s/srv_gen/lisp'%pkg_dir 00809 if (not os.path.exists(output_dir)): 00810 # if we're being run concurrently, the above test can report false but os.makedirs can still fail if 00811 # another copy just created the directory 00812 try: 00813 os.makedirs(output_dir) 00814 except OSError as e: 00815 pass 00816 00817 ######################################## 00818 # 1. Write the .lisp file 00819 ######################################## 00820 00821 io = StringIO() 00822 s = IndentedWriter(io) 00823 write_begin(s, spec, srv_path, True) 00824 spec.request.actual_name='%s-request'%spec.short_name 00825 spec.response.actual_name='%s-response'%spec.short_name 00826 write_srv_component(s, spec.request, spec) 00827 s.newline() 00828 write_srv_component(s, spec.response, spec) 00829 write_service_specific_methods(s, spec) 00830 00831 with open('%s/%s.lisp'%(output_dir, spec.short_name), 'w') as f: 00832 f.write(io.getvalue()) 00833 io.close() 00834 00835 ######################################## 00836 # 2. Write the _package file 00837 # for this service 00838 ######################################## 00839 00840 io = StringIO() 00841 s = IndentedWriter(io) 00842 write_accessor_exports(s, spec) 00843 with open('%s/_package_%s.lisp'%(output_dir, spec.short_name), 'w') as f: 00844 f.write(io.getvalue()) 00845 io.close() 00846 00847 ######################################## 00848 # 3. Write the _package.lisp file 00849 ######################################## 00850 00851 io = StringIO() 00852 s = IndentedWriter(io) 00853 write_srv_exports(s, pkg) 00854 with open('%s/_package.lisp'%output_dir, 'w') as f: 00855 f.write(io.getvalue()) 00856 io.close() 00857 00858 ######################################## 00859 # 4. Write the .asd file 00860 ######################################## 00861 00862 io = StringIO() 00863 s = IndentedWriter(io) 00864 write_srv_asd(s, pkg) 00865 with open('%s/%s-srv.asd'%(output_dir, pkg), 'w') as f: 00866 f.write(io.getvalue()) 00867 io.close() 00868 00869 00870 00871 00872 if __name__ == "__main__": 00873 roslib.msgs.set_verbose(False) 00874 if sys.argv[1].endswith('.msg'): 00875 generate_msg(sys.argv[1]) 00876 elif sys.argv[1].endswith('.srv'): 00877 generate_srv(sys.argv[1]) 00878 else: 00879 raise ValueError('Invalid filename %s'%sys.argv[1])