ardupilot/libraries/APM_BinComm/APM_BinComm.h
DrZiplok@gmail.com c0c28f8eae Recover 256 bytes of RAM by making the packet transmission code smarter. Now we emit the packet directly from the procedure parameters, rather than wasting time and space packing it into a temporary buffer.
Revert the buffer overflow test until I can work out what James was doing with it.

Don't try to send a text message in response to a message we don't like; we should probably implement a NAK message instead.

Improve the text string sender a bit.  We need to fix the protocol generator for this to be less sucky on the send side.


git-svn-id: https://arducopter.googlecode.com/svn/trunk@827 f9c3cf11-9bcb-44bc-f272-b75c42450872
2010-11-11 07:16:32 +00:00

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