Code for autonomous ground vehicle, Data Bus, 3rd place winner in 2012 Sparkfun AVC.

Dependencies:   Watchdog mbed Schedule SimpleFilter LSM303DLM PinDetect DebounceIn Servo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers protocol.h Source File

protocol.h

00001 #ifndef  _MAVLINK_PROTOCOL_H_
00002 #define  _MAVLINK_PROTOCOL_H_
00003 
00004 #include "string.h"
00005 #include "checksum.h"
00006 
00007 #include "mavlink_types.h"
00008 
00009 
00010 /**
00011  * @brief Initialize the communication stack
00012  *
00013  * This function has to be called before using commParseBuffer() to initialize the different status registers.
00014  *
00015  * @return Will initialize the different buffers and status registers.
00016  */
00017 static void mavlink_parse_state_initialize(mavlink_status_t* initStatus)
00018 {
00019     if ((initStatus->parse_state <= MAVLINK_PARSE_STATE_UNINIT) || (initStatus->parse_state > MAVLINK_PARSE_STATE_GOT_CRC1))
00020     {
00021         initStatus->ck_a = 0;
00022         initStatus->ck_b = 0;
00023         initStatus->msg_received = 0;
00024         initStatus->buffer_overrun = 0;
00025         initStatus->parse_error = 0;
00026         initStatus->parse_state = MAVLINK_PARSE_STATE_UNINIT;
00027         initStatus->packet_idx = 0;
00028         initStatus->packet_rx_drop_count = 0;
00029         initStatus->packet_rx_success_count = 0;
00030         initStatus->current_rx_seq = 0;
00031         initStatus->current_tx_seq = 0;
00032     }
00033 }
00034 
00035 static inline mavlink_status_t* mavlink_get_channel_status(uint8_t chan)
00036 {
00037     static mavlink_status_t m_mavlink_status[MAVLINK_COMM_NUM_BUFFERS];
00038     return &m_mavlink_status[chan];
00039 }
00040 
00041 /**
00042  * @brief Finalize a MAVLink message with MAVLINK_COMM_0 as default channel
00043  *
00044  * This function calculates the checksum and sets length and aircraft id correctly.
00045  * It assumes that the message id and the payload are already correctly set. 
00046  *
00047  * @warning This function implicitely assumes the message is sent over channel zero.
00048  *          if the message is sent over a different channel it will reach the receiver
00049  *          without error, BUT the sequence number might be wrong due to the wrong
00050  *          channel sequence counter. This will result is wrongly reported excessive
00051  *          packet loss. Please use @see mavlink_{pack|encode}_headerless and then
00052  *          @see mavlink_finalize_message_chan before sending for a correct channel
00053  *          assignment. Please note that the mavlink_msg_xxx_pack and encode functions
00054  *          assign channel zero as default and thus induce possible loss counter errors.\
00055  *          They have been left to ensure code compatibility.
00056  *
00057  * @see mavlink_finalize_message_chan
00058  * @param msg Message to finalize
00059  * @param system_id Id of the sending (this) system, 1-127
00060  * @param length Message length, usually just the counter incremented while packing the message
00061  */
00062 static inline uint16_t mavlink_finalize_message(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, uint16_t length)
00063 {
00064     // This code part is the same for all messages;
00065     uint16_t checksum;
00066     msg->len = length;
00067     msg->sysid = system_id;
00068     msg->compid = component_id;
00069     // One sequence number per component
00070     msg->seq = mavlink_get_channel_status(MAVLINK_COMM_0)->current_tx_seq;
00071     mavlink_get_channel_status(MAVLINK_COMM_0)->current_tx_seq = mavlink_get_channel_status(MAVLINK_COMM_0)->current_tx_seq+1;
00072     checksum = crc_calculate((uint8_t*)((void*)msg), length + MAVLINK_CORE_HEADER_LEN);
00073     msg->ck_a = (uint8_t)(checksum & 0xFF); ///< High byte
00074     msg->ck_b = (uint8_t)(checksum >> 8); ///< Low byte
00075 
00076     return length + MAVLINK_NUM_NON_STX_PAYLOAD_BYTES;
00077 }
00078 
00079 /**
00080  * @brief Finalize a MAVLink message with channel assignment
00081  *
00082  * This function calculates the checksum and sets length and aircraft id correctly.
00083  * It assumes that the message id and the payload are already correctly set. This function
00084  * can also be used if the message header has already been written before (as in mavlink_msg_xxx_pack
00085  * instead of mavlink_msg_xxx_pack_headerless), it just introduces little extra overhead.
00086  *
00087  * @param msg Message to finalize
00088  * @param system_id Id of the sending (this) system, 1-127
00089  * @param length Message length, usually just the counter incremented while packing the message
00090  */
00091 static inline uint16_t mavlink_finalize_message_chan(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, uint8_t chan, uint16_t length)
00092 {
00093     // This code part is the same for all messages;
00094     uint16_t checksum;
00095     msg->len = length;
00096     msg->sysid = system_id;
00097     msg->compid = component_id;
00098     // One sequence number per component
00099     msg->seq = mavlink_get_channel_status(chan)->current_tx_seq;
00100     mavlink_get_channel_status(chan)->current_tx_seq = mavlink_get_channel_status(chan)->current_tx_seq+1;
00101     checksum = crc_calculate((uint8_t*)((void*)msg), length + MAVLINK_CORE_HEADER_LEN);
00102     msg->ck_a = (uint8_t)(checksum & 0xFF); ///< High byte
00103     msg->ck_b = (uint8_t)(checksum >> 8); ///< Low byte
00104 
00105     return length + MAVLINK_NUM_NON_STX_PAYLOAD_BYTES;
00106 }
00107 
00108 /**
00109  * @brief Pack a message to send it over a serial byte stream
00110  */
00111 static inline uint16_t mavlink_msg_to_send_buffer(uint8_t* buffer, const mavlink_message_t* msg)
00112 {
00113     *(buffer+0) = MAVLINK_STX; ///< Start transmit
00114     memcpy((buffer+1), msg, msg->len + MAVLINK_CORE_HEADER_LEN); ///< Core header plus payload
00115     *(buffer + msg->len + MAVLINK_CORE_HEADER_LEN + 1) = msg->ck_a;
00116     *(buffer + msg->len + MAVLINK_CORE_HEADER_LEN + 2) = msg->ck_b;
00117     return msg->len + MAVLINK_NUM_NON_PAYLOAD_BYTES;
00118     //return 0;
00119 }
00120 
00121 /**
00122  * @brief Get the required buffer size for this message
00123  */
00124 static inline uint16_t mavlink_msg_get_send_buffer_length(const mavlink_message_t* msg)
00125 {
00126     return msg->len + MAVLINK_NUM_NON_PAYLOAD_BYTES;
00127 }
00128 
00129 union checksum_ {
00130     uint16_t s;
00131     uint8_t c[2];
00132 };
00133 
00134 union __mavlink_bitfield {
00135     uint8_t uint8;
00136     int8_t int8;
00137     uint16_t uint16;
00138     int16_t int16;
00139     uint32_t uint32;
00140     int32_t int32;
00141 };
00142 
00143 
00144 static inline void mavlink_start_checksum(mavlink_message_t* msg)
00145 {
00146     union checksum_ ck;
00147     crc_init(&(ck.s));
00148     msg->ck_a = ck.c[0];
00149     msg->ck_b = ck.c[1];
00150 }
00151 
00152 static inline void mavlink_update_checksum(mavlink_message_t* msg, uint8_t c)
00153 {
00154     union checksum_ ck;
00155     ck.c[0] = msg->ck_a;
00156     ck.c[1] = msg->ck_b;
00157     crc_accumulate(c, &(ck.s));
00158     msg->ck_a = ck.c[0];
00159     msg->ck_b = ck.c[1];
00160 }
00161 
00162 /**
00163  * This is a convenience function which handles the complete MAVLink parsing.
00164  * the function will parse one byte at a time and return the complete packet once
00165  * it could be successfully decoded. Checksum and other failures will be silently
00166  * ignored.
00167  *
00168  * @param chan     ID of the current channel. This allows to parse different channels with this function.
00169  *                 a channel is not a physical message channel like a serial port, but a logic partition of
00170  *                 the communication streams in this case. COMM_NB is the limit for the number of channels
00171  *                 on MCU (e.g. ARM7), while COMM_NB_HIGH is the limit for the number of channels in Linux/Windows
00172  * @param c        The char to barse
00173  *
00174  * @param returnMsg NULL if no message could be decoded, the message data else
00175  * @return 0 if no message could be decoded, 1 else
00176  *
00177  * A typical use scenario of this function call is:
00178  *
00179  * @code
00180  * #include <inttypes.h> // For fixed-width uint8_t type
00181  *
00182  * mavlink_message_t msg;
00183  * int chan = 0;
00184  *
00185  *
00186  * while(serial.bytesAvailable > 0)
00187  * {
00188  *   uint8_t byte = serial.getNextByte();
00189  *   if (mavlink_parse_char(chan, byte, &msg))
00190  *     {
00191  *     printf("Received message with ID %d, sequence: %d from component %d of system %d", msg.msgid, msg.seq, msg.compid, msg.sysid);
00192  *     }
00193  * }
00194  *
00195  *
00196  * @endcode
00197  */
00198 static inline uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_message_t* r_message, mavlink_status_t* r_mavlink_status)
00199 {
00200     static mavlink_message_t m_mavlink_message[MAVLINK_COMM_NUM_BUFFERS];
00201 
00202     // Initializes only once, values keep unchanged after first initialization
00203     mavlink_parse_state_initialize(mavlink_get_channel_status(chan));
00204 
00205     mavlink_message_t* rxmsg = &m_mavlink_message[chan]; ///< The currently decoded message
00206     mavlink_status_t* status = mavlink_get_channel_status(chan); ///< The current decode status
00207     int bufferIndex = 0;
00208 
00209     status->msg_received = 0;
00210 
00211     switch (status->parse_state)
00212     {
00213     case MAVLINK_PARSE_STATE_UNINIT:
00214     case MAVLINK_PARSE_STATE_IDLE:
00215         if (c == MAVLINK_STX)
00216         {
00217             status->parse_state = MAVLINK_PARSE_STATE_GOT_STX;
00218             mavlink_start_checksum(rxmsg);
00219         }
00220         break;
00221 
00222     case MAVLINK_PARSE_STATE_GOT_STX:
00223         if (status->msg_received)
00224         {
00225             status->buffer_overrun++;
00226             status->parse_error++;
00227             status->msg_received = 0;
00228             status->parse_state = MAVLINK_PARSE_STATE_IDLE;
00229         }
00230         else
00231         {
00232             // NOT counting STX, LENGTH, SEQ, SYSID, COMPID, MSGID, CRC1 and CRC2
00233             rxmsg->len = c;
00234             status->packet_idx = 0;
00235             mavlink_update_checksum(rxmsg, c);
00236             status->parse_state = MAVLINK_PARSE_STATE_GOT_LENGTH;
00237         }
00238         break;
00239 
00240     case MAVLINK_PARSE_STATE_GOT_LENGTH:
00241         rxmsg->seq = c;
00242         mavlink_update_checksum(rxmsg, c);
00243         status->parse_state = MAVLINK_PARSE_STATE_GOT_SEQ;
00244         break;
00245 
00246     case MAVLINK_PARSE_STATE_GOT_SEQ:
00247         rxmsg->sysid = c;
00248         mavlink_update_checksum(rxmsg, c);
00249         status->parse_state = MAVLINK_PARSE_STATE_GOT_SYSID;
00250         break;
00251 
00252     case MAVLINK_PARSE_STATE_GOT_SYSID:
00253         rxmsg->compid = c;
00254         mavlink_update_checksum(rxmsg, c);
00255         status->parse_state = MAVLINK_PARSE_STATE_GOT_COMPID;
00256         break;
00257 
00258     case MAVLINK_PARSE_STATE_GOT_COMPID:
00259         rxmsg->msgid = c;
00260         mavlink_update_checksum(rxmsg, c);
00261         if (rxmsg->len == 0)
00262         {
00263             status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD;
00264         }
00265         else
00266         {
00267             status->parse_state = MAVLINK_PARSE_STATE_GOT_MSGID;
00268         }
00269         break;
00270 
00271     case MAVLINK_PARSE_STATE_GOT_MSGID:
00272         rxmsg->payload[status->packet_idx++] = c;
00273         mavlink_update_checksum(rxmsg, c);
00274         if (status->packet_idx == rxmsg->len)
00275         {
00276             status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD;
00277         }
00278         break;
00279 
00280     case MAVLINK_PARSE_STATE_GOT_PAYLOAD:
00281         if (c != rxmsg->ck_a)
00282         {
00283             // Check first checksum byte
00284             status->parse_error++;
00285             status->msg_received = 0;
00286             status->parse_state = MAVLINK_PARSE_STATE_IDLE;
00287             if (c == MAVLINK_STX)
00288             {
00289                 status->parse_state = MAVLINK_PARSE_STATE_GOT_STX;
00290                 mavlink_start_checksum(rxmsg);
00291             }
00292         }
00293         else
00294         {
00295             status->parse_state = MAVLINK_PARSE_STATE_GOT_CRC1;
00296         }
00297         break;
00298 
00299     case MAVLINK_PARSE_STATE_GOT_CRC1:
00300         if (c != rxmsg->ck_b)
00301         {// Check second checksum byte
00302             status->parse_error++;
00303             status->msg_received = 0;
00304             status->parse_state = MAVLINK_PARSE_STATE_IDLE;
00305             if (c == MAVLINK_STX)
00306             {
00307                 status->parse_state = MAVLINK_PARSE_STATE_GOT_STX;
00308                 mavlink_start_checksum(rxmsg);
00309             }
00310         }
00311         else
00312         {
00313             // Successfully got message
00314             status->msg_received = 1;
00315             status->parse_state = MAVLINK_PARSE_STATE_IDLE;
00316             memcpy(r_message, rxmsg, sizeof(mavlink_message_t));
00317         }
00318         break;
00319     }
00320 
00321     bufferIndex++;
00322     // If a message has been sucessfully decoded, check index
00323     if (status->msg_received == 1)
00324     {
00325         //while(status->current_seq != rxmsg->seq)
00326         //{
00327         //    status->packet_rx_drop_count++;
00328         //               status->current_seq++;
00329         //}
00330         status->current_rx_seq = rxmsg->seq;
00331         // Initial condition: If no packet has been received so far, drop count is undefined
00332         if (status->packet_rx_success_count == 0) status->packet_rx_drop_count = 0;
00333         // Count this packet as received
00334         status->packet_rx_success_count++;
00335     }
00336 
00337     r_mavlink_status->current_rx_seq = status->current_rx_seq+1;
00338     r_mavlink_status->packet_rx_success_count = status->packet_rx_success_count;
00339     r_mavlink_status->packet_rx_drop_count = status->parse_error;
00340     status->parse_error = 0;
00341     return status->msg_received;
00342 }
00343 
00344 
00345 /**
00346  * This is a convenience function which handles the complete MAVLink parsing.
00347  * the function will parse one byte at a time and return the complete packet once
00348  * it could be successfully decoded. Checksum and other failures will be silently
00349  * ignored.
00350  *
00351  * @param chan     ID of the current channel. This allows to parse different channels with this function.
00352  *                 a channel is not a physical message channel like a serial port, but a logic partition of
00353  *                 the communication streams in this case. COMM_NB is the limit for the number of channels
00354  *                 on MCU (e.g. ARM7), while COMM_NB_HIGH is the limit for the number of channels in Linux/Windows
00355  * @param c        The char to barse
00356  *
00357  * @param returnMsg NULL if no message could be decoded, the message data else
00358  * @return 0 if no message could be decoded, 1 else
00359  *
00360  * A typical use scenario of this function call is:
00361  *
00362  * @code
00363  * #include <inttypes.h> // For fixed-width uint8_t type
00364  *
00365  * mavlink_message_t msg;
00366  * int chan = 0;
00367  *
00368  *
00369  * while(serial.bytesAvailable > 0)
00370  * {
00371  *   uint8_t byte = serial.getNextByte();
00372  *   if (mavlink_parse_char(chan, byte, &msg))
00373  *     {
00374  *     printf("Received message with ID %d, sequence: %d from component %d of system %d", msg.msgid, msg.seq, msg.compid, msg.sysid);
00375  *     }
00376  * }
00377  *
00378  *
00379  * @endcode
00380  */
00381 
00382 #define MAVLINK_PACKET_START_CANDIDATES 50
00383 /*
00384 static inline uint8_t mavlink_parse_char_new(uint8_t chan, uint8_t c, mavlink_message_t* r_message, mavlink_status_t* r_mavlink_status)
00385 {
00386         static mavlink_status_t m_mavlink_status[MAVLINK_COMM_NUM_BUFFERS];
00387         static uint8_t m_msgbuf[MAVLINK_COMM_NUM_BUFFERS][MAVLINK_MAX_PACKET_LEN * 2];
00388         static uint8_t m_msgbuf_index[MAVLINK_COMM_NUM_BUFFERS];
00389         static mavlink_message_t m_mavlink_message[MAVLINK_COMM_NUM_BUFFERS];
00390         static uint8_t m_packet_start[MAVLINK_COMM_NUM_BUFFERS][MAVLINK_PACKET_START_CANDIDATES];
00391         static uint8_t m_packet_start_index_read[MAVLINK_COMM_NUM_BUFFERS];
00392         static uint8_t m_packet_start_index_write[MAVLINK_COMM_NUM_BUFFERS];
00393 
00394         // Set a packet start candidate index if sign is start sign
00395         if (c == MAVLINK_STX)
00396         {
00397             m_packet_start[chan][++(m_packet_start_index_write[chan]) % MAVLINK_PACKET_START_CANDIDATES] = m_msgbuf_index[chan];
00398         }
00399 
00400         // Parse normally, if a CRC mismatch occurs retry with the next packet index
00401 }
00402 //    static mavlink_status_t m_mavlink_status[MAVLINK_COMM_NUM_BUFFERS];
00403 //    static mavlink_message_t m_mavlink_message[MAVLINK_COMM_NUM_BUFFERS];
00404 //// Initializes only once, values keep unchanged after first initialization
00405 //    mavlink_parse_state_initialize(&m_mavlink_status[chan]);
00406 //
00407 //mavlink_message_t* rxmsg = &m_mavlink_message[chan]; ///< The currently decoded message
00408 //mavlink_status_t* status = &m_mavlink_status[chan]; ///< The current decode status
00409 //int bufferIndex = 0;
00410 //
00411 //status->msg_received = 0;
00412 //
00413 //switch (status->parse_state)
00414 //{
00415 //case MAVLINK_PARSE_STATE_UNINIT:
00416 //case MAVLINK_PARSE_STATE_IDLE:
00417 //            if (c == MAVLINK_STX)
00418 //    {
00419 //        status->parse_state = MAVLINK_PARSE_STATE_GOT_STX;
00420 //        mavlink_start_checksum(rxmsg);
00421 //    }
00422 //    break;
00423 //
00424 //case MAVLINK_PARSE_STATE_GOT_STX:
00425 //    if (status->msg_received)
00426 //    {
00427 //        status->buffer_overrun++;
00428 //        status->parse_error++;
00429 //        status->msg_received = 0;
00430 //        status->parse_state = MAVLINK_PARSE_STATE_IDLE;
00431 //    }
00432 //    else
00433 //    {
00434 //        // NOT counting STX, LENGTH, SEQ, SYSID, COMPID, MSGID, CRC1 and CRC2
00435 //        rxmsg->len = c;
00436 //        status->packet_idx = 0;
00437 //        mavlink_update_checksum(rxmsg, c);
00438 //        status->parse_state = MAVLINK_PARSE_STATE_GOT_LENGTH;
00439 //    }
00440 //    break;
00441 //
00442 //case MAVLINK_PARSE_STATE_GOT_LENGTH:
00443 //    rxmsg->seq = c;
00444 //    mavlink_update_checksum(rxmsg, c);
00445 //    status->parse_state = MAVLINK_PARSE_STATE_GOT_SEQ;
00446 //    break;
00447 //
00448 //case MAVLINK_PARSE_STATE_GOT_SEQ:
00449 //    rxmsg->sysid = c;
00450 //    mavlink_update_checksum(rxmsg, c);
00451 //    status->parse_state = MAVLINK_PARSE_STATE_GOT_SYSID;
00452 //    break;
00453 //
00454 //case MAVLINK_PARSE_STATE_GOT_SYSID:
00455 //    rxmsg->compid = c;
00456 //    mavlink_update_checksum(rxmsg, c);
00457 //    status->parse_state = MAVLINK_PARSE_STATE_GOT_COMPID;
00458 //    break;
00459 //
00460 //case MAVLINK_PARSE_STATE_GOT_COMPID:
00461 //    rxmsg->msgid = c;
00462 //    mavlink_update_checksum(rxmsg, c);
00463 //    if (rxmsg->len == 0)
00464 //    {
00465 //        status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD;
00466 //    }
00467 //    else
00468 //    {
00469 //        status->parse_state = MAVLINK_PARSE_STATE_GOT_MSGID;
00470 //    }
00471 //    break;
00472 //
00473 //case MAVLINK_PARSE_STATE_GOT_MSGID:
00474 //    rxmsg->payload[status->packet_idx++] = c;
00475 //    mavlink_update_checksum(rxmsg, c);
00476 //    if (status->packet_idx == rxmsg->len)
00477 //    {
00478 //        status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD;
00479 //    }
00480 //    break;
00481 //
00482 //case MAVLINK_PARSE_STATE_GOT_PAYLOAD:
00483 //    if (c != rxmsg->ck_a)
00484 //    {
00485 //        // Check first checksum byte
00486 //        status->parse_error++;
00487 //        status->msg_received = 0;
00488 //        status->parse_state = MAVLINK_PARSE_STATE_IDLE;
00489 //    }
00490 //    else
00491 //    {
00492 //        status->parse_state = MAVLINK_PARSE_STATE_GOT_CRC1;
00493 //    }
00494 //    break;
00495 //
00496 //case MAVLINK_PARSE_STATE_GOT_CRC1:
00497 //    if (c != rxmsg->ck_b)
00498 //    {// Check second checksum byte
00499 //        status->parse_error++;
00500 //        status->msg_received = 0;
00501 //        status->parse_state = MAVLINK_PARSE_STATE_IDLE;
00502 //    }
00503 //    else
00504 //    {
00505 //        // Successfully got message
00506 //        status->msg_received = 1;
00507 //        status->parse_state = MAVLINK_PARSE_STATE_IDLE;
00508 //        memcpy(r_message, rxmsg, sizeof(mavlink_message_t));
00509 //    }
00510 //    break;
00511 //}
00512 
00513 bufferIndex++;
00514 // If a message has been sucessfully decoded, check index
00515 if (status->msg_received == 1)
00516 {
00517     //while(status->current_seq != rxmsg->seq)
00518     //{
00519     //    status->packet_rx_drop_count++;
00520     //               status->current_seq++;
00521     //}
00522     status->current_seq = rxmsg->seq;
00523     // Initial condition: If no packet has been received so far, drop count is undefined
00524     if (status->packet_rx_success_count == 0) status->packet_rx_drop_count = 0;
00525     // Count this packet as received
00526     status->packet_rx_success_count++;
00527 }
00528 
00529 r_mavlink_status->current_seq = status->current_seq+1;
00530 r_mavlink_status->packet_rx_success_count = status->packet_rx_success_count;
00531 r_mavlink_status->packet_rx_drop_count = status->parse_error;
00532 return status->msg_received;
00533 }
00534  */
00535 
00536 
00537 typedef union __generic_16bit
00538 {
00539     uint8_t b[2];
00540     int16_t s;
00541 } generic_16bit;
00542 
00543 typedef union __generic_32bit
00544 {
00545     uint8_t b[4];
00546     float f;
00547     int32_t i;
00548     int16_t s;
00549 } generic_32bit;
00550 
00551 typedef union __generic_64bit
00552 {
00553     uint8_t b[8];
00554     int64_t ll; ///< Long long (64 bit)
00555     double  d;  ///< IEEE-754 double precision floating point
00556 } generic_64bit;
00557 
00558 /**
00559  * @brief Place an unsigned byte into the buffer
00560  *
00561  * @param b the byte to add
00562  * @param bindex the position in the packet
00563  * @param buffer the packet buffer
00564  * @return the new position of the last used byte in the buffer
00565  */
00566 static inline uint8_t put_uint8_t_by_index(uint8_t b, uint8_t bindex, uint8_t* buffer)
00567 {
00568     *(buffer + bindex) = b;
00569     return sizeof(b);
00570 }
00571 
00572 /**
00573  * @brief Place a signed byte into the buffer
00574  *
00575  * @param b the byte to add
00576  * @param bindex the position in the packet
00577  * @param buffer the packet buffer
00578  * @return the new position of the last used byte in the buffer
00579  */
00580 static inline uint8_t put_int8_t_by_index(int8_t b, int8_t bindex, uint8_t* buffer)
00581 {
00582     *(buffer + bindex) = (uint8_t)b;
00583     return sizeof(b);
00584 }
00585 
00586 /**
00587  * @brief Place two unsigned bytes into the buffer
00588  *
00589  * @param b the bytes to add
00590  * @param bindex the position in the packet
00591  * @param buffer the packet buffer
00592  * @return the new position of the last used byte in the buffer
00593  */
00594 static inline uint8_t put_uint16_t_by_index(uint16_t b, const uint8_t bindex, uint8_t* buffer)
00595 {
00596     buffer[bindex]   = (b>>8)&0xff;
00597     buffer[bindex+1] = (b & 0xff);
00598     return sizeof(b);
00599 }
00600 
00601 /**
00602  * @brief Place two signed bytes into the buffer
00603  *
00604  * @param b the bytes to add
00605  * @param bindex the position in the packet
00606  * @param buffer the packet buffer
00607  * @return the new position of the last used byte in the buffer
00608  */
00609 static inline uint8_t put_int16_t_by_index(int16_t b, uint8_t bindex, uint8_t* buffer)
00610 {
00611     return put_uint16_t_by_index(b, bindex, buffer);
00612 }
00613 
00614 /**
00615  * @brief Place four unsigned bytes into the buffer
00616  *
00617  * @param b the bytes to add
00618  * @param bindex the position in the packet
00619  * @param buffer the packet buffer
00620  * @return the new position of the last used byte in the buffer
00621  */
00622 static inline uint8_t put_uint32_t_by_index(uint32_t b, const uint8_t bindex, uint8_t* buffer)
00623 {
00624     buffer[bindex]   = (b>>24)&0xff;
00625     buffer[bindex+1] = (b>>16)&0xff;
00626     buffer[bindex+2] = (b>>8)&0xff;
00627     buffer[bindex+3] = (b & 0xff);
00628     return sizeof(b);
00629 }
00630 
00631 /**
00632  * @brief Place four signed bytes into the buffer
00633  *
00634  * @param b the bytes to add
00635  * @param bindex the position in the packet
00636  * @param buffer the packet buffer
00637  * @return the new position of the last used byte in the buffer
00638  */
00639 static inline uint8_t put_int32_t_by_index(int32_t b, uint8_t bindex, uint8_t* buffer)
00640 {
00641     buffer[bindex]   = (b>>24)&0xff;
00642     buffer[bindex+1] = (b>>16)&0xff;
00643     buffer[bindex+2] = (b>>8)&0xff;
00644     buffer[bindex+3] = (b & 0xff);
00645     return sizeof(b);
00646 }
00647 
00648 /**
00649  * @brief Place four unsigned bytes into the buffer
00650  *
00651  * @param b the bytes to add
00652  * @param bindex the position in the packet
00653  * @param buffer the packet buffer
00654  * @return the new position of the last used byte in the buffer
00655  */
00656 static inline uint8_t put_uint64_t_by_index(uint64_t b, const uint8_t bindex, uint8_t* buffer)
00657 {
00658     buffer[bindex]   = (b>>56)&0xff;
00659     buffer[bindex+1] = (b>>48)&0xff;
00660     buffer[bindex+2] = (b>>40)&0xff;
00661     buffer[bindex+3] = (b>>32)&0xff;
00662     buffer[bindex+4] = (b>>24)&0xff;
00663     buffer[bindex+5] = (b>>16)&0xff;
00664     buffer[bindex+6] = (b>>8)&0xff;
00665     buffer[bindex+7] = (b & 0xff);
00666     return sizeof(b);
00667 }
00668 
00669 /**
00670  * @brief Place four signed bytes into the buffer
00671  *
00672  * @param b the bytes to add
00673  * @param bindex the position in the packet
00674  * @param buffer the packet buffer
00675  * @return the new position of the last used byte in the buffer
00676  */
00677 static inline uint8_t put_int64_t_by_index(int64_t b, uint8_t bindex, uint8_t* buffer)
00678 {
00679     return put_uint64_t_by_index(b, bindex, buffer);
00680 }
00681 
00682 /**
00683  * @brief Place a float into the buffer
00684  *
00685  * @param b the float to add
00686  * @param bindex the position in the packet
00687  * @param buffer the packet buffer
00688  * @return the new position of the last used byte in the buffer
00689  */
00690 static inline uint8_t put_float_by_index(float b, uint8_t bindex, uint8_t* buffer)
00691 {
00692     generic_32bit g;
00693     g.f = b;
00694     return put_int32_t_by_index(g.i, bindex, buffer);
00695 }
00696 
00697 /**
00698  * @brief Place a double into the buffer
00699  *
00700  * @param b the double to add
00701  * @param bindex the position in the packet
00702  * @param buffer the packet buffer
00703  * @return the new position of the last used byte in the buffer
00704  */
00705 static inline uint8_t put_double_by_index(double b, uint8_t bindex, uint8_t* buffer)
00706 {
00707     generic_64bit g;
00708     g.d = b;
00709     return put_int64_t_by_index(g.ll, bindex, buffer);
00710 }
00711 
00712 /**
00713  * @brief Place an array into the buffer
00714  *
00715  * @param b the array to add
00716  * @param length size of the array (for strings: length WITH '\0' char)
00717  * @param bindex the position in the packet
00718  * @param buffer packet buffer
00719  * @return new position of the last used byte in the buffer
00720  */
00721 static inline uint8_t put_array_by_index(const int8_t* b, uint8_t length, uint8_t bindex, uint8_t* buffer)
00722 {
00723     memcpy(buffer+bindex, b, length);
00724     return length;
00725 }
00726 
00727 /**
00728  * @brief Place a string into the buffer
00729  *
00730  * @param b the string to add
00731  * @param maxlength size of the array (for strings: length WITHOUT '\0' char)
00732  * @param bindex the position in the packet
00733  * @param buffer packet buffer
00734  * @return new position of the last used byte in the buffer
00735  */
00736 static inline uint8_t put_string_by_index(const char* b, uint8_t maxlength, uint8_t bindex, uint8_t* buffer)
00737 {
00738     uint16_t length = 0;
00739     // Copy string into buffer, ensuring not to exceed the buffer size
00740     int i;
00741     for (i = 1; i < maxlength; i++)
00742     {
00743         length++;
00744         // String characters
00745         if (i < (maxlength - 1))
00746         {
00747             buffer[bindex+i] = b[i];
00748             // Stop at null character
00749             if (b[i] == '\0')
00750             {
00751                 break;
00752             }
00753         }
00754         // Enforce null termination at end of buffer
00755         else if (i == (maxlength - 1))
00756         {
00757             buffer[i] = '\0';
00758         }
00759     }
00760     // Write length into first field
00761     put_uint8_t_by_index(length, bindex, buffer);
00762     return length;
00763 }
00764 
00765 /**
00766  * @brief Put a bitfield of length 1-32 bit into the buffer
00767  *
00768  * @param b the value to add, will be encoded in the bitfield
00769  * @param bits number of bits to use to encode b, e.g. 1 for boolean, 2, 3, etc.
00770  * @param packet_index the position in the packet (the index of the first byte to use)
00771  * @param bit_index the position in the byte (the index of the first bit to use)
00772  * @param buffer packet buffer to write into
00773  * @return new position of the last used byte in the buffer
00774  */
00775 static inline uint8_t put_bitfield_n_by_index(int32_t b, uint8_t bits, uint8_t packet_index, uint8_t bit_index, uint8_t* r_bit_index, uint8_t* buffer)
00776 {
00777     uint16_t bits_remain = bits;
00778     // Transform number into network order
00779     generic_32bit bin;
00780     generic_32bit bout;
00781     uint8_t i_bit_index, i_byte_index, curr_bits_n;
00782     bin.i = b;
00783     bout.b[0] = bin.b[3];
00784     bout.b[1] = bin.b[2];
00785     bout.b[2] = bin.b[1];
00786     bout.b[3] = bin.b[0];
00787 
00788     // buffer in
00789     // 01100000 01000000 00000000 11110001
00790     // buffer out
00791     // 11110001 00000000 01000000 01100000
00792 
00793     // Existing partly filled byte (four free slots)
00794     // 0111xxxx
00795 
00796     // Mask n free bits
00797     // 00001111 = 2^0 + 2^1 + 2^2 + 2^3 = 2^n - 1
00798     // = ((uint32_t)(1 << n)) - 1; // = 2^n - 1
00799 
00800     // Shift n bits into the right position
00801     // out = in >> n;
00802 
00803     // Mask and shift bytes
00804     i_bit_index = bit_index;
00805     i_byte_index = packet_index;
00806     if (bit_index > 0)
00807     {
00808         // If bits were available at start, they were available
00809         // in the byte before the current index
00810         i_byte_index--;
00811     }
00812 
00813     // While bits have not been packed yet
00814     while (bits_remain > 0)
00815     {
00816         // Bits still have to be packed
00817         // there can be more than 8 bits, so
00818         // we might have to pack them into more than one byte
00819 
00820         // First pack everything we can into the current 'open' byte
00821         //curr_bits_n = bits_remain << 3; // Equals  bits_remain mod 8
00822         //FIXME
00823         if (bits_remain <= (8 - i_bit_index))
00824         {
00825             // Enough space
00826             curr_bits_n = bits_remain;
00827         }
00828         else
00829         {
00830             curr_bits_n = (8 - i_bit_index);
00831         }
00832         
00833         // Pack these n bits into the current byte
00834         // Mask out whatever was at that position with ones (xxx11111)
00835         buffer[i_byte_index] &= (0xFF >> (8 - curr_bits_n));
00836         // Put content to this position, by masking out the non-used part
00837         buffer[i_byte_index] |= ((0x00 << curr_bits_n) & bout.i);
00838         
00839         // Increment the bit index
00840         i_bit_index += curr_bits_n;
00841 
00842         // Now proceed to the next byte, if necessary
00843         bits_remain -= curr_bits_n;
00844         if (bits_remain > 0)
00845         {
00846             // Offer another 8 bits / one byte
00847             i_byte_index++;
00848             i_bit_index = 0;
00849         }
00850     }
00851     
00852     *r_bit_index = i_bit_index;
00853     // If a partly filled byte is present, mark this as consumed
00854     if (i_bit_index != 7) i_byte_index++;
00855     return i_byte_index - packet_index;
00856 }
00857 
00858 #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS
00859 
00860 // To make MAVLink work on your MCU, define a similar function
00861 
00862 /*
00863 
00864 #include "mavlink_types.h"
00865 
00866 void comm_send_ch(mavlink_channel_t chan, uint8_t ch)
00867 {
00868     if (chan == MAVLINK_COMM_0)
00869     {
00870         uart0_transmit(ch);
00871     }
00872     if (chan == MAVLINK_COMM_1)
00873     {
00874         uart1_transmit(ch);
00875     }
00876 }
00877  */
00878 
00879 static inline void mavlink_send_uart_uint8_t(mavlink_channel_t chan, uint8_t b, uint16_t* checksum)
00880 {
00881     crc_accumulate(b, checksum);
00882     comm_send_ch(chan, b);
00883 }
00884 
00885 static inline void mavlink_send_uart_int8_t(mavlink_channel_t chan, int8_t b, uint16_t* checksum)
00886 {
00887     crc_accumulate(b, checksum);
00888     comm_send_ch(chan, b);
00889 }
00890 
00891 static inline void mavlink_send_uart_uint16_t(mavlink_channel_t chan, uint16_t b, uint16_t* checksum)
00892 {
00893     char s;
00894     s = (b>>8)&0xff;
00895     comm_send_ch(chan, s);
00896     crc_accumulate(s, checksum);
00897     s = (b & 0xff);
00898     comm_send_ch(chan, s);
00899     crc_accumulate(s, checksum);
00900 }
00901 
00902 static inline void mavlink_send_uart_int16_t(mavlink_channel_t chan, int16_t b, uint16_t* checksum)
00903 {
00904     mavlink_send_uart_uint16_t(chan, b, checksum);
00905 }
00906 
00907 static inline void mavlink_send_uart_uint32_t(mavlink_channel_t chan, uint32_t b, uint16_t* checksum)
00908 {
00909     char s;
00910     s = (b>>24)&0xff;
00911     comm_send_ch(chan, s);
00912     crc_accumulate(s, checksum);
00913     s = (b>>16)&0xff;
00914     comm_send_ch(chan, s);
00915     crc_accumulate(s, checksum);
00916     s = (b>>8)&0xff;
00917     comm_send_ch(chan, s);
00918     crc_accumulate(s, checksum);
00919     s = (b & 0xff);
00920     comm_send_ch(chan, s);
00921     crc_accumulate(s, checksum);
00922 }
00923 
00924 static inline void mavlink_send_uart_int32_t(mavlink_channel_t chan, int32_t b, uint16_t* checksum)
00925 {
00926     mavlink_send_uart_uint32_t(chan, b, checksum);
00927 }
00928 
00929 static inline void mavlink_send_uart_uint64_t(mavlink_channel_t chan, uint64_t b, uint16_t* checksum)
00930 {
00931     char s;
00932     s = (b>>56)&0xff;
00933     comm_send_ch(chan, s);
00934     crc_accumulate(s, checksum);
00935     s = (b>>48)&0xff;
00936     comm_send_ch(chan, s);
00937     crc_accumulate(s, checksum);
00938     s = (b>>40)&0xff;
00939     comm_send_ch(chan, s);
00940     crc_accumulate(s, checksum);
00941     s = (b>>32)&0xff;
00942     comm_send_ch(chan, s);
00943     crc_accumulate(s, checksum);
00944     s = (b>>24)&0xff;
00945     comm_send_ch(chan, s);
00946     crc_accumulate(s, checksum);
00947     s = (b>>16)&0xff;
00948     comm_send_ch(chan, s);
00949     crc_accumulate(s, checksum);
00950     s = (b>>8)&0xff;
00951     comm_send_ch(chan, s);
00952     crc_accumulate(s, checksum);
00953     s = (b & 0xff);
00954     comm_send_ch(chan, s);
00955     crc_accumulate(s, checksum);
00956 }
00957 
00958 static inline void mavlink_send_uart_int64_t(mavlink_channel_t chan, int64_t b, uint16_t* checksum)
00959 {
00960     mavlink_send_uart_uint64_t(chan, b, checksum);
00961 }
00962 
00963 static inline void mavlink_send_uart_float(mavlink_channel_t chan, float b, uint16_t* checksum)
00964 {
00965     generic_32bit g;
00966     g.f = b;
00967     mavlink_send_uart_uint32_t(chan, g.i, checksum);
00968 }
00969 
00970 static inline void mavlink_send_uart_double(mavlink_channel_t chan, double b, uint16_t* checksum)
00971 {
00972     generic_64bit g;
00973     g.d = b;
00974     mavlink_send_uart_uint32_t(chan, g.ll, checksum);
00975 }
00976 
00977 static inline void mavlink_send_uart(mavlink_channel_t chan, mavlink_message_t* msg)
00978 {
00979     // ARM7 MCU board implementation
00980     // Create pointer on message struct
00981     // Send STX
00982     comm_send_ch(chan, MAVLINK_STX);
00983     comm_send_ch(chan, msg->len);
00984     comm_send_ch(chan, msg->seq);
00985     comm_send_ch(chan, msg->sysid);
00986     comm_send_ch(chan, msg->compid);
00987     comm_send_ch(chan, msg->msgid);
00988     for(uint16_t i = 0; i < msg->len; i++)
00989     {
00990         comm_send_ch(chan, msg->payload[i]);
00991     }
00992     comm_send_ch(chan, msg->ck_a);
00993     comm_send_ch(chan, msg->ck_b);
00994 }
00995 #endif
00996 
00997 #endif /* _MAVLINK_PROTOCOL_H_ */