ardupilot/libraries/APM_BinComm/APM_BinComm.h

356 lines
11 KiB
C++

// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*-
//
// Copyright (c) 2010 Michael Smith. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
/// @file BinComm.h
/// @brief Definitions for the ArduPilot Mega binary communications
/// library.
#ifndef APM_BinComm_h
#define APM_BinComm_h
#include <string.h>
#include <inttypes.h>
#include "WProgram.h"
///
/// @class BinComm
/// @brief Class providing protocol en/decoding services for the ArduPilot
/// Mega binary telemetry protocol.
///
/// The protocol definition, including structures describing
/// messages, MessageID values and helper functions for sending
/// and unpacking messages are automatically generated.
///
/// See protocol/protocol.def for a description of the message
/// definitions, and protocol/protocol.h for the generated
/// definitions.
///
/// Protocol messages are sent using the send_* functions defined in
/// protocol/protocol.h, and handled on reception by functions defined
/// in the handlerTable array passed to the constructor.
///
class BinComm {
public:
struct MessageHandler;
//////////////////////////////////////////////////////////////////////
/// Constructor.
///
/// @param handlerTable Array of callout functions to which
/// received messages will be sent. More than
/// one handler for a given messageID may be
/// registered; handlers are called in the order
/// they appear in the table. A single handler
/// may be registered for more than one message,
/// as the message ID is passed to the handler
/// when it is received.
///
/// @param interface The stream that will be used
/// for telemetry communications.
///
/// @param rxBuffSize Size of receive buffer allocated by interface.
/// This is used to warn for buffer overflow.
///
///
BinComm(const MessageHandler *handlerTable,
Stream *interface = NULL);
///
/// Optional initialiser.
///
/// If the interface stream isn't known at construction time, it
/// can be set here instead.
///
/// @param interface The stream that will be used for telemetry
/// communications.
///
void init(Stream *interface);
private:
/// OTA message header
struct MessageHeader {
uint8_t length;
uint8_t messageID;
uint8_t messageVersion;
};
/// Incoming header/packet buffer
/// XXX we could make this smaller
union {
uint8_t bytes[0];
MessageHeader header;
uint8_t payload[256];
} _decodeBuf;
//////////////////////////////////////////////////////////////////////
/// @name Message pack/unpack utility functions
///
//@{
/// Emit any scalar type.
///
/// @param x Value to emit.
///
template <typename T> inline void _emit(const T x) { _send(&x, sizeof(T)); }
/// Emit an array of any scalar type.
///
/// @param x Array to emit.
/// @param count Array size.
///
template <typename T> inline void _emit(const T *values, uint8_t count) { _send(values, count * sizeof(T)); }
/// Emit a fixed-size string, from a NUL-terminated buffer.
///
/// The string is NUL-padded if the buffer is larger than the string.
///
/// @param msg The NUL-terminated string to emit.
/// @param size The maximum length of the string to emit.
///
inline void _emit(const char *msg, uint8_t size) {
while (size--) {
char c = *msg;
_emit(c);
if (0 != c)
msg++;
}
}
/// Unpack any scalar type.
///
/// @param buf Buffer pointer.
/// @param x Unpacked result.
///
template <typename T> inline void _unpack(uint8_t *&ptr, T &x) { x = *(T *)ptr; ptr += sizeof(T); }
/// Unpack an array of any scalar type.
///
/// @param buf Buffer pointer.
/// @param values Array to receive the unpacked values.
///
template <typename T> inline void _unpack(uint8_t *&ptr, T *values, uint8_t count) {
memcpy(values, ptr, count * sizeof(T));
ptr += count * sizeof(T);
}
/// Unpack a string from a fixed-size buffer.
///
/// @param ptr Buffer pointer.
/// @param msg Pointer to the result buffer.
/// @param size The size of the buffer.
///
inline void _unpack(uint8_t *&ptr, char *msg, uint8_t size) {
strncpy(msg, (char *)ptr, size); msg[size-1] = '\0'; ptr += size;
}
//@}
public:
//////////////////////////////////////////////////////////////////////
/// @name Protocol definition
///
//@{
#include "protocol/protocol.h"
//@}
//////////////////////////////////////////////////////////////////////
/// @name Protocol magic numbers
///
/// @note The MessageID enum is automatically generated and thus not described here.
///
//@{
/// Message serverities
enum severities
{
SEVERITY_LOW = 1,
SEVERITY_MEDIUM = 2,
SEVERITY_HIGH = 3,
SEVERITY_CRITICAL = 4,
};
/// Variables defined
/// XXX these should probably be handled by the database/MIB?
enum variableID {
MSG_VAR_ROLL_MODE = 0x00,
MSG_VAR_PITCH_MODE = 0x01,
MSG_VAR_THROTTLE_MODE = 0x02,
MSG_VAR_YAW_MODE = 0x03,
MSG_VAR_ELEVON_TRIM_1 = 0x04,
MSG_VAR_ELEVON_TRIM_2 = 0x05,
MSG_VAR_INTEGRATOR_0 = 0x10,
MSG_VAR_INTEGRATOR_1 = 0x11,
MSG_VAR_INTEGRATOR_2 = 0x12,
MSG_VAR_INTEGRATOR_3 = 0x13,
MSG_VAR_INTEGRATOR_4 = 0x14,
MSG_VAR_INTEGRATOR_5 = 0x15,
MSG_VAR_INTEGRATOR_6 = 0x16,
MSG_VAR_INTEGRATOR_7 = 0x17,
MSG_VAR_KFF_0 = 0x1a,
MSG_VAR_KFF_1 = 0x1b,
MSG_VAR_KFF_2 = 0x1c,
MSG_VAR_TARGET_BEARING = 0x20,
MSG_VAR_NAV_BEARING = 0x21,
MSG_VAR_BEARING_ERROR = 0x22,
MSG_VAR_CROSSTRACK_BEARING = 0x23,
MSG_VAR_CROSSTRACK_ERROR = 0x24,
MSG_VAR_ALTITUDE_ERROR = 0x25,
MSG_VAR_WP_RADIUS = 0x26,
MSG_VAR_LOITER_RADIUS = 0x27,
MSG_VAR_WP_MODE = 0x28,
MSG_VAR_LOOP_COMMANDS = 0x29,
MSG_VAR_NAV_GAIN_SCALER = 0x2a,
};
/// PID sets defined
enum PIDSet {
MSG_SERVO_ROLL = 0,
MSG_SERVO_PITCH = 1,
MSG_SERVO_RUDDER = 2,
MSG_SERVO_NAV_ROLL = 3,
MSG_SERVO_NAV_PITCH_ASP = 4,
MSG_SERVO_NAV_PITCH_ALT = 5,
MSG_SERVO_TE_THROTTLE = 6,
MSG_SERVO_ALT_THROTTLE = 7,
MSG_SERVO_ELEVATOR = 8 // Added by Randy
};
//@}
//////////////////////////////////////////////////////////////////////
/// Message reception callout descriptor
///
/// An array of these handlers is passed to the constructor to delegate
/// processing for received messages.
///
struct MessageHandler {
MessageID messageID; ///< messageID for which the handler will be called
void (* handler)(void *arg,
uint8_t messageId,
uint8_t messageVersion,
void *messageData); ///< function to be called
void *arg; ///< argument passed to function
};
//////////////////////////////////////////////////////////////////////
/// @name Decoder interface
//@{
/// Consume bytes from the interface and feed them to the decoder.
///
/// If a packet is completed, then any callbacks associated
/// with the packet's messageID will be called.
///
/// If no bytes are passed to the decoder for a period determined
/// by DEC_MESSAGE_TIMEOUT, the decode state machine will reset
/// before processing the next byte. This can help re-synchronise
/// after a link loss or in-flight failure.
///
void update(void);
uint32_t messagesReceived; ///< statistics
uint32_t badMessagesReceived; ///< statistics
//@}
//////////////////////////////////////////////////////////////////////
/// @name Encoder interface
///
/// Messages are normally encoded and sent using the
/// send_msg_* functions defined in protocol/protocol.h.
/// For each message type MSG_* there is a corresponding send_msg_*
/// function which will construct and transmit the message.
///
//@{
uint32_t messagesSent; ///< statistics
//@}
private:
const MessageHandler *_handlerTable; ///< callout table
Stream *_interface; ///< Serial port we send/receive using.
/// Various magic numbers
enum MagicNumbers {
MSG_PREAMBLE_1 = 0x34,
MSG_PREAMBLE_2 = 0x44,
MSG_VERSION_1 = 1,
MSG_VARIABLE_LENGTH = 0xff
};
//////////////////////////////////////////////////////////////////////
/// @name Decoder state
//@{
uint8_t _decodePhase; ///< decoder state machine phase
uint8_t _bytesIn; ///< bytes received in the current phase
uint8_t _bytesExpected; ///< bytes expected in the current phase
uint8_t _decoderSumA; ///< sum of incoming bytes
uint8_t _decoderSumB; ///< sum of _sumA values
uint8_t _messageID; ///< messageID from the packet being received
uint8_t _messageVersion;///< messageVersion from the packet being received
unsigned long _lastReceived; ///< timestamp of last byte reception
//@}
/// Decoder state machine.
///
/// @param inByte The byte to process.
///
void _decode(uint8_t inByte);
//////////////////////////////////////////////////////////////////////
/// @name Encoder state
//@{
uint8_t _encoderSumA; ///< sum of outgoing bytes
uint8_t _encoderSumB; ///< sum of _sumA values
//@}
/// Start transmitting a message.
///
/// @param messageId The ID of the message to be sent
/// @param messageLength The protocol-defined length of the message in bytes
/// @param messageVersion The message version (optional)
///
void _startMessage(uint8_t messageId, uint8_t messageLength, uint8_t messageVersion = 1);
/// Send bytes as part of a message.
///
/// @param bytes Pointer to the byte(s) to send.
/// @param count Count of bytes to send.
void _send(const void *bytes, uint8_t count);
/// Finalise message transmission.
///
void _endMessage(void);
};
#endif // BinComm_h