mavgen_c.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. #!/usr/bin/env python
  2. '''
  3. parse a MAVLink protocol XML file and generate a C implementation
  4. Copyright Andrew Tridgell 2011
  5. Released under GNU GPL version 3 or later
  6. '''
  7. from __future__ import print_function
  8. from future.utils import iteritems
  9. from builtins import range
  10. from builtins import object
  11. import os
  12. from . import mavparse, mavtemplate
  13. t = mavtemplate.MAVTemplate()
  14. def generate_version_h(directory, xml):
  15. '''generate version.h'''
  16. f = open(os.path.join(directory, "version.h"), mode='w')
  17. t.write(f,'''
  18. /** @file
  19. * @brief MAVLink comm protocol built from ${basename}.xml
  20. * @see http://mavlink.org
  21. */
  22. #pragma once
  23. #ifndef MAVLINK_VERSION_H
  24. #define MAVLINK_VERSION_H
  25. #define MAVLINK_BUILD_DATE "${parse_time}"
  26. #define MAVLINK_WIRE_PROTOCOL_VERSION "${wire_protocol_version}"
  27. #define MAVLINK_MAX_DIALECT_PAYLOAD_SIZE ${largest_payload}
  28. #endif // MAVLINK_VERSION_H
  29. ''', xml)
  30. f.close()
  31. def generate_mavlink_h(directory, xml):
  32. '''generate mavlink.h'''
  33. f = open(os.path.join(directory, "mavlink.h"), mode='w')
  34. t.write(f,'''
  35. /** @file
  36. * @brief MAVLink comm protocol built from ${basename}.xml
  37. * @see http://mavlink.org
  38. */
  39. #pragma once
  40. #ifndef MAVLINK_H
  41. #define MAVLINK_H
  42. #define MAVLINK_PRIMARY_XML_IDX ${xml_idx}
  43. #ifndef MAVLINK_STX
  44. #define MAVLINK_STX ${protocol_marker}
  45. #endif
  46. #ifndef MAVLINK_ENDIAN
  47. #define MAVLINK_ENDIAN ${mavlink_endian}
  48. #endif
  49. #ifndef MAVLINK_ALIGNED_FIELDS
  50. #define MAVLINK_ALIGNED_FIELDS ${aligned_fields_define}
  51. #endif
  52. #ifndef MAVLINK_CRC_EXTRA
  53. #define MAVLINK_CRC_EXTRA ${crc_extra_define}
  54. #endif
  55. #ifndef MAVLINK_COMMAND_24BIT
  56. #define MAVLINK_COMMAND_24BIT ${command_24bit_define}
  57. #endif
  58. #include "version.h"
  59. #include "${basename}.h"
  60. #endif // MAVLINK_H
  61. ''', xml)
  62. f.close()
  63. def generate_main_h(directory, xml):
  64. '''generate main header per XML file'''
  65. f = open(os.path.join(directory, xml.basename + ".h"), mode='w')
  66. t.write(f, '''
  67. /** @file
  68. * @brief MAVLink comm protocol generated from ${basename}.xml
  69. * @see http://mavlink.org
  70. */
  71. #pragma once
  72. #ifndef MAVLINK_${basename_upper}_H
  73. #define MAVLINK_${basename_upper}_H
  74. #ifndef MAVLINK_H
  75. #error Wrong include order: MAVLINK_${basename_upper}.H MUST NOT BE DIRECTLY USED. Include mavlink.h from the same directory instead or set ALL AND EVERY defines from MAVLINK.H manually accordingly, including the #define MAVLINK_H call.
  76. #endif
  77. #undef MAVLINK_THIS_XML_IDX
  78. #define MAVLINK_THIS_XML_IDX ${xml_idx}
  79. #ifdef __cplusplus
  80. extern "C" {
  81. #endif
  82. // MESSAGE LENGTHS AND CRCS
  83. #ifndef MAVLINK_MESSAGE_LENGTHS
  84. #define MAVLINK_MESSAGE_LENGTHS {${message_lengths_array}}
  85. #endif
  86. #ifndef MAVLINK_MESSAGE_CRCS
  87. #define MAVLINK_MESSAGE_CRCS {${message_crcs_array}}
  88. #endif
  89. #include "../protocol.h"
  90. #define MAVLINK_ENABLED_${basename_upper}
  91. // ENUM DEFINITIONS
  92. ${{enum:
  93. /** @brief ${description} */
  94. #ifndef HAVE_ENUM_${name}
  95. #define HAVE_ENUM_${name}
  96. typedef enum ${name}
  97. {
  98. ${{entry: ${name}=${value}, /* ${description} |${{param:${description}| }} */
  99. }}
  100. } ${name};
  101. #endif
  102. }}
  103. // MAVLINK VERSION
  104. #ifndef MAVLINK_VERSION
  105. #define MAVLINK_VERSION ${version}
  106. #endif
  107. #if (MAVLINK_VERSION == 0)
  108. #undef MAVLINK_VERSION
  109. #define MAVLINK_VERSION ${version}
  110. #endif
  111. // MESSAGE DEFINITIONS
  112. ${{message:#include "./mavlink_msg_${name_lower}.h"
  113. }}
  114. // base include
  115. ${{include_list:#include "../${base}/${base}.h"
  116. }}
  117. #undef MAVLINK_THIS_XML_IDX
  118. #define MAVLINK_THIS_XML_IDX ${xml_idx}
  119. #if MAVLINK_THIS_XML_IDX == MAVLINK_PRIMARY_XML_IDX
  120. # define MAVLINK_MESSAGE_INFO {${message_info_array}}
  121. # define MAVLINK_MESSAGE_NAMES {${message_name_array}}
  122. # if MAVLINK_COMMAND_24BIT
  123. # include "../mavlink_get_info.h"
  124. # endif
  125. #endif
  126. #ifdef __cplusplus
  127. }
  128. #endif // __cplusplus
  129. #endif // MAVLINK_${basename_upper}_H
  130. ''', xml)
  131. f.close()
  132. def generate_message_h(directory, m):
  133. '''generate per-message header for a XML file'''
  134. f = open(os.path.join(directory, 'mavlink_msg_%s.h' % m.name_lower), mode='w')
  135. t.write(f, '''
  136. #pragma once
  137. // MESSAGE ${name} PACKING
  138. #define MAVLINK_MSG_ID_${name} ${id}
  139. MAVPACKED(
  140. typedef struct __mavlink_${name_lower}_t {
  141. ${{ordered_fields: ${type} ${name}${array_suffix}; /*< ${units} ${description}*/
  142. }}
  143. }) mavlink_${name_lower}_t;
  144. #define MAVLINK_MSG_ID_${name}_LEN ${wire_length}
  145. #define MAVLINK_MSG_ID_${name}_MIN_LEN ${wire_min_length}
  146. #define MAVLINK_MSG_ID_${id}_LEN ${wire_length}
  147. #define MAVLINK_MSG_ID_${id}_MIN_LEN ${wire_min_length}
  148. #define MAVLINK_MSG_ID_${name}_CRC ${crc_extra}
  149. #define MAVLINK_MSG_ID_${id}_CRC ${crc_extra}
  150. ${{array_fields:#define MAVLINK_MSG_${msg_name}_FIELD_${name_upper}_LEN ${array_length}
  151. }}
  152. #if MAVLINK_COMMAND_24BIT
  153. #define MAVLINK_MESSAGE_INFO_${name} { \\
  154. ${id}, \\
  155. "${name}", \\
  156. ${num_fields}, \\
  157. { ${{fields: { "${name}", ${c_print_format}, MAVLINK_TYPE_${type_upper}, ${array_length}, ${wire_offset}, offsetof(mavlink_${name_lower}_t, ${name}) }, \\
  158. }} } \\
  159. }
  160. #else
  161. #define MAVLINK_MESSAGE_INFO_${name} { \\
  162. "${name}", \\
  163. ${num_fields}, \\
  164. { ${{fields: { "${name}", ${c_print_format}, MAVLINK_TYPE_${type_upper}, ${array_length}, ${wire_offset}, offsetof(mavlink_${name_lower}_t, ${name}) }, \\
  165. }} } \\
  166. }
  167. #endif
  168. /**
  169. * @brief Pack a ${name_lower} message
  170. * @param system_id ID of this system
  171. * @param component_id ID of this component (e.g. 200 for IMU)
  172. * @param msg The MAVLink message to compress the data into
  173. *
  174. ${{arg_fields: * @param ${name} ${units} ${description}
  175. }}
  176. * @return length of the message in bytes (excluding serial stream start sign)
  177. */
  178. static inline uint16_t mavlink_msg_${name_lower}_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg,
  179. ${{arg_fields: ${array_const}${type} ${array_prefix}${name},}})
  180. {
  181. #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS
  182. char buf[MAVLINK_MSG_ID_${name}_LEN];
  183. ${{scalar_fields: _mav_put_${type}(buf, ${wire_offset}, ${putname});
  184. }}
  185. ${{array_fields: _mav_put_${type}_array(buf, ${wire_offset}, ${name}, ${array_length});
  186. }}
  187. memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_${name}_LEN);
  188. #else
  189. mavlink_${name_lower}_t packet;
  190. ${{scalar_fields: packet.${name} = ${putname};
  191. }}
  192. ${{array_fields: mav_array_memcpy(packet.${name}, ${name}, sizeof(${type})*${array_length});
  193. }}
  194. memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_${name}_LEN);
  195. #endif
  196. msg->msgid = MAVLINK_MSG_ID_${name};
  197. return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_${name}_MIN_LEN, MAVLINK_MSG_ID_${name}_LEN, MAVLINK_MSG_ID_${name}_CRC);
  198. }
  199. /**
  200. * @brief Pack a ${name_lower} message on a channel
  201. * @param system_id ID of this system
  202. * @param component_id ID of this component (e.g. 200 for IMU)
  203. * @param chan The MAVLink channel this message will be sent over
  204. * @param msg The MAVLink message to compress the data into
  205. ${{arg_fields: * @param ${name} ${units} ${description}
  206. }}
  207. * @return length of the message in bytes (excluding serial stream start sign)
  208. */
  209. static inline uint16_t mavlink_msg_${name_lower}_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan,
  210. mavlink_message_t* msg,
  211. ${{arg_fields:${array_const}${type} ${array_prefix}${name},}})
  212. {
  213. #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS
  214. char buf[MAVLINK_MSG_ID_${name}_LEN];
  215. ${{scalar_fields: _mav_put_${type}(buf, ${wire_offset}, ${putname});
  216. }}
  217. ${{array_fields: _mav_put_${type}_array(buf, ${wire_offset}, ${name}, ${array_length});
  218. }}
  219. memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_${name}_LEN);
  220. #else
  221. mavlink_${name_lower}_t packet;
  222. ${{scalar_fields: packet.${name} = ${putname};
  223. }}
  224. ${{array_fields: mav_array_memcpy(packet.${name}, ${name}, sizeof(${type})*${array_length});
  225. }}
  226. memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_${name}_LEN);
  227. #endif
  228. msg->msgid = MAVLINK_MSG_ID_${name};
  229. return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_${name}_MIN_LEN, MAVLINK_MSG_ID_${name}_LEN, MAVLINK_MSG_ID_${name}_CRC);
  230. }
  231. /**
  232. * @brief Encode a ${name_lower} struct
  233. *
  234. * @param system_id ID of this system
  235. * @param component_id ID of this component (e.g. 200 for IMU)
  236. * @param msg The MAVLink message to compress the data into
  237. * @param ${name_lower} C-struct to read the message contents from
  238. */
  239. static inline uint16_t mavlink_msg_${name_lower}_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_${name_lower}_t* ${name_lower})
  240. {
  241. return mavlink_msg_${name_lower}_pack(system_id, component_id, msg,${{arg_fields: ${name_lower}->${name},}});
  242. }
  243. /**
  244. * @brief Encode a ${name_lower} struct on a channel
  245. *
  246. * @param system_id ID of this system
  247. * @param component_id ID of this component (e.g. 200 for IMU)
  248. * @param chan The MAVLink channel this message will be sent over
  249. * @param msg The MAVLink message to compress the data into
  250. * @param ${name_lower} C-struct to read the message contents from
  251. */
  252. static inline uint16_t mavlink_msg_${name_lower}_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_${name_lower}_t* ${name_lower})
  253. {
  254. return mavlink_msg_${name_lower}_pack_chan(system_id, component_id, chan, msg,${{arg_fields: ${name_lower}->${name},}});
  255. }
  256. /**
  257. * @brief Send a ${name_lower} message
  258. * @param chan MAVLink channel to send the message
  259. *
  260. ${{arg_fields: * @param ${name} ${units} ${description}
  261. }}
  262. */
  263. #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS
  264. static inline void mavlink_msg_${name_lower}_send(mavlink_channel_t chan,${{arg_fields: ${array_const}${type} ${array_prefix}${name},}})
  265. {
  266. #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS
  267. char buf[MAVLINK_MSG_ID_${name}_LEN];
  268. ${{scalar_fields: _mav_put_${type}(buf, ${wire_offset}, ${putname});
  269. }}
  270. ${{array_fields: _mav_put_${type}_array(buf, ${wire_offset}, ${name}, ${array_length});
  271. }}
  272. _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_${name}, buf, MAVLINK_MSG_ID_${name}_MIN_LEN, MAVLINK_MSG_ID_${name}_LEN, MAVLINK_MSG_ID_${name}_CRC);
  273. #else
  274. mavlink_${name_lower}_t packet;
  275. ${{scalar_fields: packet.${name} = ${putname};
  276. }}
  277. ${{array_fields: mav_array_memcpy(packet.${name}, ${name}, sizeof(${type})*${array_length});
  278. }}
  279. _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_${name}, (const char *)&packet, MAVLINK_MSG_ID_${name}_MIN_LEN, MAVLINK_MSG_ID_${name}_LEN, MAVLINK_MSG_ID_${name}_CRC);
  280. #endif
  281. }
  282. /**
  283. * @brief Send a ${name_lower} message
  284. * @param chan MAVLink channel to send the message
  285. * @param struct The MAVLink struct to serialize
  286. */
  287. static inline void mavlink_msg_${name_lower}_send_struct(mavlink_channel_t chan, const mavlink_${name_lower}_t* ${name_lower})
  288. {
  289. #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS
  290. mavlink_msg_${name_lower}_send(chan,${{arg_fields: ${name_lower}->${name},}});
  291. #else
  292. _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_${name}, (const char *)${name_lower}, MAVLINK_MSG_ID_${name}_MIN_LEN, MAVLINK_MSG_ID_${name}_LEN, MAVLINK_MSG_ID_${name}_CRC);
  293. #endif
  294. }
  295. #if MAVLINK_MSG_ID_${name}_LEN <= MAVLINK_MAX_PAYLOAD_LEN
  296. /*
  297. This varient of _send() can be used to save stack space by re-using
  298. memory from the receive buffer. The caller provides a
  299. mavlink_message_t which is the size of a full mavlink message. This
  300. is usually the receive buffer for the channel, and allows a reply to an
  301. incoming message with minimum stack space usage.
  302. */
  303. static inline void mavlink_msg_${name_lower}_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, ${{arg_fields: ${array_const}${type} ${array_prefix}${name},}})
  304. {
  305. #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS
  306. char *buf = (char *)msgbuf;
  307. ${{scalar_fields: _mav_put_${type}(buf, ${wire_offset}, ${putname});
  308. }}
  309. ${{array_fields: _mav_put_${type}_array(buf, ${wire_offset}, ${name}, ${array_length});
  310. }}
  311. _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_${name}, buf, MAVLINK_MSG_ID_${name}_MIN_LEN, MAVLINK_MSG_ID_${name}_LEN, MAVLINK_MSG_ID_${name}_CRC);
  312. #else
  313. mavlink_${name_lower}_t *packet = (mavlink_${name_lower}_t *)msgbuf;
  314. ${{scalar_fields: packet->${name} = ${putname};
  315. }}
  316. ${{array_fields: mav_array_memcpy(packet->${name}, ${name}, sizeof(${type})*${array_length});
  317. }}
  318. _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_${name}, (const char *)packet, MAVLINK_MSG_ID_${name}_MIN_LEN, MAVLINK_MSG_ID_${name}_LEN, MAVLINK_MSG_ID_${name}_CRC);
  319. #endif
  320. }
  321. #endif
  322. #endif
  323. // MESSAGE ${name} UNPACKING
  324. ${{fields:
  325. /**
  326. * @brief Get field ${name} from ${name_lower} message
  327. *
  328. * @return ${units} ${description}
  329. */
  330. static inline ${return_type} mavlink_msg_${name_lower}_get_${name}(const mavlink_message_t* msg${get_arg})
  331. {
  332. return _MAV_RETURN_${type}${array_tag}(msg, ${array_return_arg} ${wire_offset});
  333. }
  334. }}
  335. /**
  336. * @brief Decode a ${name_lower} message into a struct
  337. *
  338. * @param msg The message to decode
  339. * @param ${name_lower} C-struct to decode the message contents into
  340. */
  341. static inline void mavlink_msg_${name_lower}_decode(const mavlink_message_t* msg, mavlink_${name_lower}_t* ${name_lower})
  342. {
  343. #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS
  344. ${{ordered_fields: ${decode_left}mavlink_msg_${name_lower}_get_${name}(msg${decode_right});
  345. }}
  346. #else
  347. uint8_t len = msg->len < MAVLINK_MSG_ID_${name}_LEN? msg->len : MAVLINK_MSG_ID_${name}_LEN;
  348. memset(${name_lower}, 0, MAVLINK_MSG_ID_${name}_LEN);
  349. memcpy(${name_lower}, _MAV_PAYLOAD(msg), len);
  350. #endif
  351. }
  352. ''', m)
  353. f.close()
  354. def generate_testsuite_h(directory, xml):
  355. '''generate testsuite.h per XML file'''
  356. f = open(os.path.join(directory, "testsuite.h"), mode='w')
  357. t.write(f, '''
  358. /** @file
  359. * @brief MAVLink comm protocol testsuite generated from ${basename}.xml
  360. * @see http://qgroundcontrol.org/mavlink/
  361. */
  362. #pragma once
  363. #ifndef ${basename_upper}_TESTSUITE_H
  364. #define ${basename_upper}_TESTSUITE_H
  365. #ifdef __cplusplus
  366. extern "C" {
  367. #endif
  368. #ifndef MAVLINK_TEST_ALL
  369. #define MAVLINK_TEST_ALL
  370. ${{include_list:static void mavlink_test_${base}(uint8_t, uint8_t, mavlink_message_t *last_msg);
  371. }}
  372. static void mavlink_test_${basename}(uint8_t, uint8_t, mavlink_message_t *last_msg);
  373. static void mavlink_test_all(uint8_t system_id, uint8_t component_id, mavlink_message_t *last_msg)
  374. {
  375. ${{include_list: mavlink_test_${base}(system_id, component_id, last_msg);
  376. }}
  377. mavlink_test_${basename}(system_id, component_id, last_msg);
  378. }
  379. #endif
  380. ${{include_list:#include "../${base}/testsuite.h"
  381. }}
  382. ${{message:
  383. static void mavlink_test_${name_lower}(uint8_t system_id, uint8_t component_id, mavlink_message_t *last_msg)
  384. {
  385. #ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1
  386. mavlink_status_t *status = mavlink_get_channel_status(MAVLINK_COMM_0);
  387. if ((status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_${name} >= 256) {
  388. return;
  389. }
  390. #endif
  391. mavlink_message_t msg;
  392. uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
  393. uint16_t i;
  394. mavlink_${name_lower}_t packet_in = {
  395. ${{ordered_fields:${c_test_value},}}
  396. };
  397. mavlink_${name_lower}_t packet1, packet2;
  398. memset(&packet1, 0, sizeof(packet1));
  399. ${{scalar_fields:packet1.${name} = packet_in.${name};
  400. }}
  401. ${{array_fields:mav_array_memcpy(packet1.${name}, packet_in.${name}, sizeof(${type})*${array_length});
  402. }}
  403. #ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1
  404. if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) {
  405. // cope with extensions
  406. memset(MAVLINK_MSG_ID_${name}_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_${name}_MIN_LEN);
  407. }
  408. #endif
  409. memset(&packet2, 0, sizeof(packet2));
  410. mavlink_msg_${name_lower}_encode(system_id, component_id, &msg, &packet1);
  411. mavlink_msg_${name_lower}_decode(&msg, &packet2);
  412. MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0);
  413. memset(&packet2, 0, sizeof(packet2));
  414. mavlink_msg_${name_lower}_pack(system_id, component_id, &msg ${{arg_fields:, packet1.${name} }});
  415. mavlink_msg_${name_lower}_decode(&msg, &packet2);
  416. MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0);
  417. memset(&packet2, 0, sizeof(packet2));
  418. mavlink_msg_${name_lower}_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg ${{arg_fields:, packet1.${name} }});
  419. mavlink_msg_${name_lower}_decode(&msg, &packet2);
  420. MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0);
  421. memset(&packet2, 0, sizeof(packet2));
  422. mavlink_msg_to_send_buffer(buffer, &msg);
  423. for (i=0; i<mavlink_msg_get_send_buffer_length(&msg); i++) {
  424. comm_send_ch(MAVLINK_COMM_0, buffer[i]);
  425. }
  426. mavlink_msg_${name_lower}_decode(last_msg, &packet2);
  427. MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0);
  428. memset(&packet2, 0, sizeof(packet2));
  429. mavlink_msg_${name_lower}_send(MAVLINK_COMM_1 ${{arg_fields:, packet1.${name} }});
  430. mavlink_msg_${name_lower}_decode(last_msg, &packet2);
  431. MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0);
  432. }
  433. }}
  434. static void mavlink_test_${basename}(uint8_t system_id, uint8_t component_id, mavlink_message_t *last_msg)
  435. {
  436. ${{message: mavlink_test_${name_lower}(system_id, component_id, last_msg);
  437. }}
  438. }
  439. #ifdef __cplusplus
  440. }
  441. #endif // __cplusplus
  442. #endif // ${basename_upper}_TESTSUITE_H
  443. ''', xml)
  444. f.close()
  445. def copy_fixed_headers(directory, xml):
  446. '''copy the fixed protocol headers to the target directory'''
  447. import shutil, filecmp
  448. hlist = {
  449. "0.9": [ 'protocol.h', 'mavlink_helpers.h', 'mavlink_types.h', 'checksum.h' ],
  450. "1.0": [ 'protocol.h', 'mavlink_helpers.h', 'mavlink_types.h', 'checksum.h', 'mavlink_conversions.h' ],
  451. "2.0": [ 'protocol.h', 'mavlink_helpers.h', 'mavlink_types.h', 'checksum.h', 'mavlink_conversions.h',
  452. 'mavlink_get_info.h', 'mavlink_sha256.h' ]
  453. }
  454. basepath = os.path.dirname(os.path.realpath(__file__))
  455. srcpath = os.path.join(basepath, 'C/include_v%s' % xml.wire_protocol_version)
  456. print("Copying fixed headers for protocol %s to %s" % (xml.wire_protocol_version, directory))
  457. for h in hlist[xml.wire_protocol_version]:
  458. src = os.path.realpath(os.path.join(srcpath, h))
  459. dest = os.path.realpath(os.path.join(directory, h))
  460. if src == dest or (os.path.exists(dest) and filecmp.cmp(src, dest)):
  461. continue
  462. shutil.copy(src, dest)
  463. class mav_include(object):
  464. def __init__(self, base):
  465. self.base = base
  466. def generate_one(basename, xml):
  467. '''generate headers for one XML file'''
  468. directory = os.path.join(basename, xml.basename)
  469. print("Generating C implementation in directory %s" % directory)
  470. mavparse.mkdir_p(directory)
  471. if xml.little_endian:
  472. xml.mavlink_endian = "MAVLINK_LITTLE_ENDIAN"
  473. else:
  474. xml.mavlink_endian = "MAVLINK_BIG_ENDIAN"
  475. if xml.crc_extra:
  476. xml.crc_extra_define = "1"
  477. else:
  478. xml.crc_extra_define = "0"
  479. if xml.command_24bit:
  480. xml.command_24bit_define = "1"
  481. else:
  482. xml.command_24bit_define = "0"
  483. if xml.sort_fields:
  484. xml.aligned_fields_define = "1"
  485. else:
  486. xml.aligned_fields_define = "0"
  487. # work out the included headers
  488. xml.include_list = []
  489. for i in xml.include:
  490. base = i[:-4]
  491. xml.include_list.append(mav_include(base))
  492. # form message lengths array
  493. xml.message_lengths_array = ''
  494. if not xml.command_24bit:
  495. for msgid in range(256):
  496. mlen = xml.message_min_lengths.get(msgid, 0)
  497. xml.message_lengths_array += '%u, ' % mlen
  498. xml.message_lengths_array = xml.message_lengths_array[:-2]
  499. # and message CRCs array
  500. xml.message_crcs_array = ''
  501. if xml.command_24bit:
  502. # we sort with primary key msgid
  503. for msgid in sorted(xml.message_crcs.keys()):
  504. xml.message_crcs_array += '{%u, %u, %u, %u, %u, %u, %u}, ' % (msgid,
  505. xml.message_crcs[msgid],
  506. xml.message_min_lengths[msgid],
  507. xml.message_lengths[msgid],
  508. xml.message_flags[msgid],
  509. xml.message_target_system_ofs[msgid],
  510. xml.message_target_component_ofs[msgid])
  511. else:
  512. for msgid in range(256):
  513. crc = xml.message_crcs.get(msgid, 0)
  514. xml.message_crcs_array += '%u, ' % crc
  515. xml.message_crcs_array = xml.message_crcs_array[:-2]
  516. # form message info array
  517. xml.message_info_array = ''
  518. if xml.command_24bit:
  519. # we sort with primary key msgid
  520. for msgid in sorted(xml.message_names.keys()):
  521. name = xml.message_names[msgid]
  522. xml.message_info_array += 'MAVLINK_MESSAGE_INFO_%s, ' % name
  523. else:
  524. for msgid in range(256):
  525. name = xml.message_names.get(msgid, None)
  526. if name is not None:
  527. xml.message_info_array += 'MAVLINK_MESSAGE_INFO_%s, ' % name
  528. else:
  529. # Several C compilers don't accept {NULL} for
  530. # multi-dimensional arrays and structs
  531. # feed the compiler a "filled" empty message
  532. xml.message_info_array += '{"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, '
  533. xml.message_info_array = xml.message_info_array[:-2]
  534. # form message name array
  535. xml.message_name_array = ''
  536. # sort by names
  537. for msgid, name in sorted(iteritems(xml.message_names), key=lambda k_v: (k_v[1], k_v[0])):
  538. xml.message_name_array += '{ "%s", %u }, ' % (name, msgid)
  539. xml.message_name_array = xml.message_name_array[:-2]
  540. # add some extra field attributes for convenience with arrays
  541. for m in xml.message:
  542. m.msg_name = m.name
  543. if xml.crc_extra:
  544. m.crc_extra_arg = ", %s" % m.crc_extra
  545. else:
  546. m.crc_extra_arg = ""
  547. for f in m.fields:
  548. if f.print_format is None:
  549. f.c_print_format = 'NULL'
  550. else:
  551. f.c_print_format = '"%s"' % f.print_format
  552. if f.array_length != 0:
  553. f.array_suffix = '[%u]' % f.array_length
  554. f.array_prefix = '*'
  555. f.array_tag = '_array'
  556. f.array_arg = ', %u' % f.array_length
  557. f.array_return_arg = '%s, %u, ' % (f.name, f.array_length)
  558. f.array_const = 'const '
  559. f.decode_left = ''
  560. f.decode_right = ', %s->%s' % (m.name_lower, f.name)
  561. f.return_type = 'uint16_t'
  562. f.get_arg = ', %s *%s' % (f.type, f.name)
  563. if f.type == 'char':
  564. f.c_test_value = '"%s"' % f.test_value
  565. else:
  566. test_strings = []
  567. for v in f.test_value:
  568. test_strings.append(str(v))
  569. f.c_test_value = '{ %s }' % ', '.join(test_strings)
  570. else:
  571. f.array_suffix = ''
  572. f.array_prefix = ''
  573. f.array_tag = ''
  574. f.array_arg = ''
  575. f.array_return_arg = ''
  576. f.array_const = ''
  577. f.decode_left = "%s->%s = " % (m.name_lower, f.name)
  578. f.decode_right = ''
  579. f.get_arg = ''
  580. f.return_type = f.type
  581. if f.type == 'char':
  582. f.c_test_value = "'%s'" % f.test_value
  583. elif f.type == 'uint64_t':
  584. f.c_test_value = "%sULL" % f.test_value
  585. elif f.type == 'int64_t':
  586. f.c_test_value = "%sLL" % f.test_value
  587. else:
  588. f.c_test_value = f.test_value
  589. # cope with uint8_t_mavlink_version
  590. for m in xml.message:
  591. m.arg_fields = []
  592. m.array_fields = []
  593. m.scalar_fields = []
  594. for f in m.ordered_fields:
  595. if f.array_length != 0:
  596. m.array_fields.append(f)
  597. else:
  598. m.scalar_fields.append(f)
  599. for f in m.fields:
  600. if not f.omit_arg:
  601. m.arg_fields.append(f)
  602. f.putname = f.name
  603. else:
  604. f.putname = f.const_value
  605. generate_mavlink_h(directory, xml)
  606. generate_version_h(directory, xml)
  607. generate_main_h(directory, xml)
  608. for m in xml.message:
  609. generate_message_h(directory, m)
  610. generate_testsuite_h(directory, xml)
  611. def generate(basename, xml_list):
  612. '''generate complete MAVLink C implemenation'''
  613. for idx in range(len(xml_list)):
  614. xml = xml_list[idx]
  615. xml.xml_idx = idx
  616. generate_one(basename, xml)
  617. copy_fixed_headers(basename, xml_list[0])