MAVLink uses one extra CRC that is added to the message CRC to detect mismatches in message specifications. This is to prevent that two devices using different message versions incorrectly decode a message with the same length.
While MAVLink 0.9 was used there were a small number of incidents where the XML describing a message that was in active use changed. The change was such that the length of the message didn't change, but the fields did. Revision 0.9 did check the correct message length, but not the field order, types or field names. This meant that when a MAV using the old code was talking to a ground station using updated code that the fields were badly corrupted. The MAVLink 0.9 protocol completely relied on everyone being careful not to change the meaning or format of any existing message. With so many people working on MAVLink this was hard to enforce. So for MAVLink 1.0 this problem was solved by adding a 1 byte 'seed' to the checksum based on the XML for the message.
As MAVLink reorders internally the message fields according to their size to prevent word / halfword alignment issues (see Data structure alignment) for further reference) and a wrongly implemented reordering potentially can cause inconsistencies as well, the CRC_EXTRA is calculated based on the internal struct and over-the-air message layout, not in the XML order.
The reordering happens as follows:
Important note: This ordering is unique and can be easily implemented in a protocol generator by using a stable sorting algorithm. The alternative to using sorting would be either to use inefficient alignment which is bad for the target architectures for typical MAVLink applications, or to have function calls in the order of the variable size instead of the application context. This would lead to very confusing function signatures of serialization functions.
This is the python code that calculates the CRC_EXTRA seed:
def message_checksum(msg): '''calculate a 8-bit checksum of the key fields of a message, so we can detect incompatible XML changes''' crc = mavutil.x25crc(msg.name + ' ') for f in msg.ordered_fields: crc.accumulate(f.type + ' ') crc.accumulate(f.name + ' ') if f.array_length: crc.accumulate(chr(f.array_length)) return (crc.crc&0xFF) ^ (crc.crc>>8)
Notice that it uses the same x25 checksum that is used at runtime. It calculates a CRC over the message name (such as “RAW_IMU”) followed by the type and name of each field, space separated. The order of the fields is the order they are sent over the wire. For arrays, the array length is also added.