3 mavlink python parse functions 5 Copyright Andrew Tridgell 2011 6 Released under GNU GPL version 3 or later 8 from __future__
import print_function
9 from builtins
import range
10 from builtins
import object
17 import xml.parsers.expat
24 FLAG_HAVE_TARGET_SYSTEM = 1
25 FLAG_HAVE_TARGET_COMPONENT = 2
28 def __init__(self, message, inner_exception=None):
36 def __init__(self, name, type, print_format, xml, description='', enum='', display='', units=''):
53 'uint8_t_mavlink_version' : 1,
62 if type==
'uint8_t_mavlink_version':
69 assert type[-1:] ==
']' 77 elif (type+
"_t")
in lengths:
89 '''generate a testsuite value for a MAVField''' 92 elif self.
type ==
'float':
93 return 17.0 + self.wire_offset*7 + i
94 elif self.
type ==
'double':
95 return 123.0 + self.wire_offset*7 + i
96 elif self.
type ==
'char':
97 return chr(ord(
'A') + (self.wire_offset + i)%26)
98 elif self.
type in [
'int8_t',
'uint8_t' ]:
99 return (5 + self.wire_offset*67 + i) & 0xFF
100 elif self.
type in [
'int16_t',
'uint16_t']:
101 return (17235 + self.wire_offset*52 + i) & 0xFFFF
102 elif self.
type in [
'int32_t',
'uint32_t']:
103 return (963497464 + self.wire_offset*52 + i)&0xFFFFFFFF
104 elif self.
type in [
'int64_t',
'uint64_t']:
105 return 93372036854775807 + self.wire_offset*63 + i
110 '''set a testsuite value for a MAVField''' 125 def __init__(self, name, id, linenumber, description=''):
136 '''return number of non-extended fields''' 142 def __init__(self, index, description='', label='', units='', enum='', increment='', minValue='', maxValue='', reserved=False, default=''):
158 if not description.strip()
and self.
reserved:
165 def __init__(self, name, value, description='', end_marker=False, autovalue=False, origin_file='', origin_line=0):
176 def __init__(self, name, linenumber, description=''):
185 '''parse a mavlink XML file''' 186 def __init__(self, filename, wire_protocol_version=PROTOCOL_0_9):
189 if self.basename.lower().endswith(
".xml"):
202 if wire_protocol_version == PROTOCOL_0_9:
210 elif wire_protocol_version == PROTOCOL_1_0:
218 elif wire_protocol_version == PROTOCOL_2_0:
227 print(
"Unknown wire protocol version")
228 print(
"Available versions are: %s %s" % (PROTOCOL_0_9, PROTOCOL_1_0, PROTOCOL_2_0))
229 raise MAVParseError(
'Unknown MAVLink wire protocol version %s' % wire_protocol_version)
233 def check_attrs(attrs, check, where):
236 raise MAVParseError(
'expected missing %s "%s" attribute at %s:%u' % (
237 where, c, filename, p.CurrentLineNumber))
239 def start_element(name, attrs):
240 in_element_list.append(name)
241 in_element =
'.'.join(in_element_list)
243 if in_element ==
"mavlink.messages.message":
244 check_attrs(attrs, [
'name',
'id'],
'message')
245 self.message.append(
MAVType(attrs[
'name'], attrs[
'id'], p.CurrentLineNumber))
246 elif in_element ==
"mavlink.messages.message.extensions":
248 elif in_element ==
"mavlink.messages.message.field":
249 check_attrs(attrs, [
'name',
'type'],
'field')
250 print_format = attrs.get(
'print_format',
None)
251 enum = attrs.get(
'enum',
'')
252 display = attrs.get(
'display',
'')
253 units = attrs.get(
'units',
'')
255 units =
'[' + units +
']' 256 new_field =
MAVField(attrs[
'name'], attrs[
'type'], print_format, self, enum=enum, display=display, units=units)
258 self.
message[-1].fields.append(new_field)
259 elif in_element ==
"mavlink.enums.enum":
260 check_attrs(attrs, [
'name'],
'enum')
261 self.enum.append(
MAVEnum(attrs[
'name'], p.CurrentLineNumber))
262 elif in_element ==
"mavlink.enums.enum.entry":
263 check_attrs(attrs, [
'name'],
'enum entry')
266 value = eval(attrs[
'value'])
269 value = self.
enum[-1].highest_value + 1
272 if (self.
enum[-1].start_value
is None or value < self.
enum[-1].start_value):
273 self.
enum[-1].start_value = value
275 if (value > self.
enum[-1].highest_value):
276 self.
enum[-1].highest_value = value
278 self.
enum[-1].entry.append(
MAVEnumEntry(attrs[
'name'], value,
'',
False, autovalue, self.
filename, p.CurrentLineNumber))
279 elif in_element ==
"mavlink.enums.enum.entry.param":
280 check_attrs(attrs, [
'index'],
'enum param')
281 self.
enum[-1].entry[-1].param.append(
283 label=attrs.get(
'label',
''), units=attrs.get(
'units',
''),
284 enum=attrs.get(
'enum',
''), increment=attrs.get(
'increment',
''),
285 minValue=attrs.get(
'minValue',
''),
286 maxValue=attrs.get(
'maxValue',
''), default=attrs.get(
'default',
'0'),
287 reserved=attrs.get(
'reserved',
False) ))
289 def is_target_system_field(m, f):
290 if f.name ==
'target_system':
292 if m.name ==
"MANUAL_CONTROL" and f.name ==
"target":
296 def end_element(name):
297 in_element_list.pop()
300 in_element =
'.'.join(in_element_list)
301 if in_element ==
"mavlink.messages.message.description":
302 self.
message[-1].description += data
303 elif in_element ==
"mavlink.messages.message.field":
305 self.
message[-1].fields[-1].description += data
306 elif in_element ==
"mavlink.enums.enum.description":
307 self.
enum[-1].description += data
308 elif in_element ==
"mavlink.enums.enum.entry.description":
309 self.
enum[-1].entry[-1].description += data
310 elif in_element ==
"mavlink.enums.enum.entry.param":
311 self.
enum[-1].entry[-1].param[-1].set_description(data.strip())
312 elif in_element ==
"mavlink.version":
314 elif in_element ==
"mavlink.include":
315 self.include.append(data)
317 f = open(filename, mode=
'rb')
318 p = xml.parsers.expat.ParserCreate()
319 p.StartElementHandler = start_element
320 p.EndElementHandler = end_element
321 p.CharacterDataHandler = char_data
327 for current_enum
in self.
enum:
328 if not 'MAV_CMD' in current_enum.name:
330 print(current_enum.name)
331 for enum_entry
in current_enum.entry:
332 print(enum_entry.name)
333 if len(enum_entry.param) == 7:
336 for param_index
in range (1,8):
337 params_dict[param_index] =
MAVEnumParam(param_index, label=
'', units=
'', enum=
'', increment=
'',
338 minValue=
'', maxValue=
'', default=
'0', reserved=
'True')
340 for a_param
in enum_entry.param:
341 params_dict[
int(a_param.index)] = a_param
342 enum_entry.param=params_dict.values()
362 print(
"Ignoring MAVLink2 message %s" % m.name)
370 m.wire_min_length = 0
373 m.ordered_fieldnames = []
374 m.ordered_fieldtypes = []
377 m.target_system_ofs = 0
378 m.target_component_ofs = 0
382 sort_end = m.base_fields()
383 m.ordered_fields = sorted(m.fields[:sort_end],
384 key=operator.attrgetter(
'type_length'),
386 m.ordered_fields.extend(m.fields[sort_end:])
388 m.ordered_fields = m.fields
390 m.fieldnames.append(f.name)
393 m.fieldlengths.append(1)
394 elif L > 1
and f.type ==
'char':
395 m.fieldlengths.append(1)
397 m.fieldlengths.append(L)
398 m.fieldtypes.append(f.type)
399 for i
in range(len(m.ordered_fields)):
400 f = m.ordered_fields[i]
401 f.wire_offset = m.wire_length
402 m.wire_length += f.wire_length
403 if m.extensions_start
is None or i < m.extensions_start:
404 m.wire_min_length = m.wire_length
405 m.ordered_fieldnames.append(f.name)
406 m.ordered_fieldtypes.append(f.type)
408 if f.name.find(
'[') != -1:
409 raise MAVParseError(
"invalid field name with array descriptor %s" % f.name)
411 if is_target_system_field(m, f):
412 m.message_flags |= FLAG_HAVE_TARGET_SYSTEM
413 m.target_system_ofs = f.wire_offset
414 elif f.name ==
'target_component':
415 m.message_flags |= FLAG_HAVE_TARGET_COMPONENT
416 m.target_component_ofs = f.wire_offset
417 m.num_fields = len(m.fieldnames)
418 if m.num_fields > 64:
419 raise MAVParseError(
"num_fields=%u : Maximum number of field names allowed is" % (
435 if m.wire_length+8 > 64:
436 print(
"Note: message %s is longer than 64 bytes long (%u bytes), which can cause fragmentation since many radio modems use 64 bytes as maximum air transfer unit." % (m.name, m.wire_length+8))
439 return "MAVXML for %s from %s (%u message, %u enums)" % (
444 '''calculate a 8-bit checksum of the key fields of a message, so we 445 can detect incompatible XML changes''' 446 from .mavcrc
import x25crc
448 crc.accumulate_str(msg.name +
' ')
451 crc_end = msg.base_fields()
452 for i
in range(crc_end):
453 f = msg.ordered_fields[i]
454 crc.accumulate_str(f.type +
' ')
455 crc.accumulate_str(f.name +
' ')
457 crc.accumulate([f.array_length])
458 return (crc.crc&0xFF) ^ (crc.crc>>8)
461 '''merge enums between XML files''' 466 if enum.name
in emap:
467 emapitem = emap[enum.name]
469 if (emapitem.start_value <= enum.highest_value
and emapitem.highest_value >= enum.start_value):
470 for entry
in emapitem.entry:
472 if entry.value <= enum.highest_value
and entry.autovalue
is True:
473 entry.value = enum.highest_value + 1
474 enum.highest_value = entry.value
476 emapitem.entry.extend(enum.entry)
477 if not emapitem.description:
478 emapitem.description = enum.description
479 print(
"Merged enum %s" % enum.name)
481 newenums.append(enum)
482 emap[enum.name] = enum
486 emap[e].entry = sorted(emap[e].entry,
487 key=operator.attrgetter(
'value'),
490 emap[e].entry.append(
MAVEnumEntry(
"%s_ENUM_END" % emap[e].name,
491 emap[e].entry[-1].value+1, end_marker=
True))
494 '''check for duplicate message IDs''' 505 print(
"ERROR: Duplicate message id %u for %s (%s:%u) also used by %s" % (
508 x.filename, m.linenumber,
513 if f.name
in fieldset:
514 print(
"ERROR: Duplicate field %s in message %s (%s:%u)" % (
516 x.filename, m.linenumber))
519 msgmap[key] =
'%s (%s:%u)' % (m.name, x.filename, m.linenumber)
521 if m.name
in msg_name_map:
522 print(
"ERROR: Duplicate message name %s for id:%u (%s:%u) also used by %s" % (
525 x.filename, m.linenumber,
526 msg_name_map[m.name]))
528 msg_name_map[m.name] =
'%s (%s:%u)' % (m.id, x.filename, m.linenumber)
530 for entry
in enum.entry:
531 if entry.autovalue
is True and "common.xml" not in entry.origin_file:
532 print(
"Note: An enum value was auto-generated: %s = %u" % (entry.name, entry.value))
533 s1 =
"%s.%s" % (enum.name, entry.name)
534 s2 =
"%s.%s" % (enum.name, entry.value)
535 if s1
in enummap
or s2
in enummap:
536 print(
"ERROR: Duplicate enum %s:\n\t%s = %s @ %s:%u\n\t%s" % (
537 "names" if s1
in enummap
else "values",
538 s1, entry.value, entry.origin_file, entry.origin_line,
539 enummap.get(s1)
or enummap.get(s2)))
541 enummap[s1] = enummap[s2] =
"%s.%s = %s @ %s:%u" % (enum.name, entry.name, entry.value, entry.origin_file, entry.origin_line)
548 '''count total number of msgs''' 551 count += len(x.message)
557 except OSError
as exc:
558 if exc.errno != errno.EEXIST:
message_target_component_ofs
def gen_test_value(self, i)
def __init__(self, name, id, linenumber, description='')
def __init__(self, name, linenumber, description='')
message_target_system_ofs
def check_duplicates(xml)
def __init__(self, name, type, print_format, xml, description='', enum='', display='', units='')
def __init__(self, message, inner_exception=None)
def __init__(self, index, description='', label='', units='', enum='', increment='', minValue='', maxValue='', reserved=False, default='')
def __init__(self, filename, wire_protocol_version=PROTOCOL_0_9)
def message_checksum(msg)
def set_description(self, description)
def __init__(self, name, value, description='', end_marker=False, autovalue=False, origin_file='', origin_line=0)