mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-11-30 08:24:11 +01:00
306 lines
8.7 KiB
C
306 lines
8.7 KiB
C
/**
|
|
******************************************************************************
|
|
* @addtogroup OpenPilotSystem OpenPilot System
|
|
* @{
|
|
* @addtogroup OpenPilotLibraries OpenPilot System Libraries
|
|
* @{
|
|
*
|
|
* @file packet_handler.c
|
|
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
|
* @brief A packet handler for handeling radio packet transmission.
|
|
* @see The GNU Public License (GPL) Version 3
|
|
*
|
|
*****************************************************************************/
|
|
/*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "openpilot.h"
|
|
#include "packet_handler.h"
|
|
#include "aes.h"
|
|
#include "crc.h"
|
|
|
|
// Private types and constants
|
|
typedef struct {
|
|
PacketHandlerConfig cfg;
|
|
PHPacket *tx_packets;
|
|
uint8_t tx_win_start;
|
|
uint8_t tx_win_end;
|
|
uint16_t tx_seq_id;
|
|
PHPacket rx_packet;
|
|
PHOutputStream stream;
|
|
xSemaphoreHandle lock;
|
|
} PHPacketData, *PHPacketDataHandle;
|
|
|
|
// Private functions
|
|
static uint8_t PHLSendAck(PHPacketDataHandle data, PHPacketHandle p);
|
|
static uint8_t PHLTransmitPacket(PHPacketDataHandle data, PHPacketHandle p);
|
|
|
|
/**
|
|
* Initialize the Packet Handler library
|
|
* \param[in] txWinSize The transmission window size (number of tx packet buffers).
|
|
* \param[in] streme A callback function for transmitting the packet.
|
|
* \param[in] id The source ID of transmitter.
|
|
* \return PHInstHandle The Pachet Handler instance data.
|
|
* \return 0 Failure
|
|
*/
|
|
PHInstHandle PHInitialize(PacketHandlerConfig *cfg)
|
|
{
|
|
// Allocate the primary structure
|
|
PHPacketDataHandle data = pvPortMalloc(sizeof(PHPacketData));
|
|
if (!data)
|
|
return 0;
|
|
data->cfg = *cfg;
|
|
data->tx_seq_id = 0;
|
|
|
|
// Allocate the tx packet window
|
|
data->tx_packets = pvPortMalloc(sizeof(PHPacket) * data->cfg.txWinSize);
|
|
|
|
// Initialize the window
|
|
data->tx_win_start = data->tx_win_end = 0;
|
|
for (uint8_t i = 0; i < data->cfg.txWinSize; ++i)
|
|
data->tx_packets[i].header.type = PACKET_TYPE_NONE;
|
|
|
|
// Create the lock
|
|
data->lock = xSemaphoreCreateRecursiveMutex();
|
|
|
|
// Return the structure.
|
|
return (PHInstHandle)data;
|
|
}
|
|
|
|
/**
|
|
* Get a packet out of the transmit buffer.
|
|
* \param[in] h The packet handler instance data pointer.
|
|
* \param[in] dest_id The destination ID of this connection
|
|
* \return PHPacketHandle A pointer to the packet buffer.
|
|
* \return 0 No packets buffers avaiable in the transmit window.
|
|
*/
|
|
uint32_t PHConnect(PHInstHandle h, uint32_t dest_id)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Temporarily reserve the next packet in the TX packet window.
|
|
* This function places a tempoary hold on the next TX packet and
|
|
* retains the packet handler lock.
|
|
*
|
|
* NOTE: PHReleaseLock must be called to release the lock and retain
|
|
* or release the reserved packet.
|
|
*
|
|
* \param[in] h The packet handler instance data pointer.
|
|
* \return PHPacketHandle A pointer to the packet buffer.
|
|
* \return 0 No packets buffers avaiable in the transmit window.
|
|
*/
|
|
PHPacketHandle PHReserveTXPacket(PHInstHandle h)
|
|
{
|
|
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
|
|
|
// Lock
|
|
xSemaphoreTakeRecursive(data->lock, portMAX_DELAY);
|
|
|
|
// Is the window full?
|
|
uint8_t next_end = (data->tx_win_end + 1) % data->cfg.txWinSize;
|
|
if(next_end == data->tx_win_start) {
|
|
|
|
// Release the lock
|
|
xSemaphoreGiveRecursive(data->lock);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Return a pointer to the packet at the end of the TX window.
|
|
return data->tx_packets + data->tx_win_end;
|
|
}
|
|
|
|
/**
|
|
* Get a packet out of the transmit buffer and keep the lock.
|
|
* NOTE: PHReleaseLock must be called to release the lock.
|
|
* \param[in] h The packet handler instance data pointer.
|
|
* \param[in] keep_packet Maintain a permanent (until released) lock on the packet.
|
|
*/
|
|
void PHReleaseLock(PHInstHandle h, bool keep_packet)
|
|
{
|
|
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
|
uint8_t next_end = (data->tx_win_end + 1) % data->cfg.txWinSize;
|
|
|
|
// Increment the end index if packet is being kept.
|
|
if (keep_packet)
|
|
data->tx_win_end = next_end;
|
|
|
|
// Release lock
|
|
xSemaphoreGiveRecursive(data->lock);
|
|
}
|
|
|
|
/**
|
|
* Get a packet out of the transmit buffer.
|
|
* \param[in] h The packet handler instance data pointer.
|
|
* \return PHPacketHandle A pointer to the packet buffer.
|
|
* \return 0 No packets buffers avaiable in the transmit window.
|
|
*/
|
|
PHPacketHandle PHGetTXPacket(PHInstHandle h)
|
|
{
|
|
PHPacketHandle p = PHReserveTXPacket(h);
|
|
PHReleaseLock(p, 1);
|
|
return p;
|
|
}
|
|
|
|
/**
|
|
* Get a pointer to the the receive buffer.
|
|
* \param[in] h The packet handler instance data pointer.
|
|
* \return PHPacketHandle A pointer to the packet buffer.
|
|
*/
|
|
PHPacketHandle PHGetRXPacket(PHInstHandle h)
|
|
{
|
|
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
|
return &(data->rx_packet);
|
|
}
|
|
|
|
/**
|
|
* Release a packet from the transmit packet buffer window.
|
|
* \param[in] h The packet handler instance data pointer.
|
|
* \param[in] p A pointer to the packet buffer.
|
|
* \return Nothing
|
|
*/
|
|
void PHReleaseTXPacket(PHInstHandle h, PHPacketHandle p)
|
|
{
|
|
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
|
|
|
// Lock
|
|
xSemaphoreTakeRecursive(data->lock, portMAX_DELAY);
|
|
|
|
// Change the packet type so we know this packet is unused.
|
|
p->header.type = PACKET_TYPE_NONE;
|
|
|
|
// If this packet is at the start of the window, increment the start index.
|
|
while ((data->tx_win_start != data->tx_win_end) &&
|
|
(data->tx_packets[data->tx_win_start].header.type == PACKET_TYPE_NONE))
|
|
data->tx_win_start = (data->tx_win_start + 1) % data->cfg.txWinSize;
|
|
|
|
// Release lock
|
|
xSemaphoreGiveRecursive(data->lock);
|
|
}
|
|
|
|
/**
|
|
* Transmit a packet from the transmit packet buffer window.
|
|
* \param[in] h The packet handler instance data pointer.
|
|
* \param[in] p A pointer to the packet buffer.
|
|
* \return 1 Success
|
|
* \return 0 Failure
|
|
*/
|
|
uint8_t PHTransmitPacket(PHInstHandle h, PHPacketHandle p)
|
|
{
|
|
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
|
|
|
// Try to transmit the packet.
|
|
if (!PHLTransmitPacket(data, p))
|
|
return 0;
|
|
|
|
// If this packet doesn't require an ACK, remove it from the TX window.
|
|
switch (p->header.type) {
|
|
case PACKET_TYPE_READY:
|
|
case PACKET_TYPE_NOTREADY:
|
|
case PACKET_TYPE_DATA:
|
|
case PACKET_TYPE_RECEIVER:
|
|
PHReleaseTXPacket(h, p);
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Process a packet that has been received.
|
|
* \param[in] h The packet handler instance data pointer.
|
|
* \param[in] p A pointer to the packet buffer.
|
|
* \return 1 Success
|
|
* \return 0 Failure
|
|
*/
|
|
uint8_t PHReceivePacket(PHInstHandle h, PHPacketHandle p)
|
|
{
|
|
PHPacketDataHandle data = (PHPacketDataHandle)h;
|
|
|
|
switch (p->header.type) {
|
|
case PACKET_TYPE_ACKED_DATA:
|
|
|
|
// Send the ACK
|
|
PHLSendAck(data, p);
|
|
|
|
// Pass on the data.
|
|
if(data->cfg.data_handler)
|
|
data->cfg.data_handler(data->cfg.dev, p->data, p->header.data_size);
|
|
|
|
break;
|
|
|
|
case PACKET_TYPE_RECEIVER:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Pass on the data to the receiver handler.
|
|
if(data->cfg.data_handler)
|
|
data->cfg.data_handler(data->cfg.dev, p->data, p->header.data_size);
|
|
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Transmit a packet from the transmit packet buffer window.
|
|
* \param[in] data The packet handler instance data pointer.
|
|
* \param[in] p A pointer to the packet buffer.
|
|
* \return 1 Success
|
|
* \return 0 Failure
|
|
*/
|
|
static uint8_t PHLTransmitPacket(PHPacketDataHandle data, PHPacketHandle p)
|
|
{
|
|
|
|
// Set the sequence ID to the current ID.
|
|
p->header.tx_seq = data->tx_seq_id++;
|
|
|
|
// Transmit the packet using the output stream.
|
|
if(!data->cfg.output_stream(data->cfg.dev, p))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Send an ACK packet.
|
|
* \param[in] data The packet handler instance data pointer.
|
|
* \param[in] p A pointer to the packet buffer of the packet to be ACKed.
|
|
* \return 1 Success
|
|
* \return 0 Failure
|
|
*/
|
|
static uint8_t PHLSendAck(PHPacketDataHandle data, PHPacketHandle p)
|
|
{
|
|
|
|
// Create the ACK message
|
|
PHPacketHeader ack;
|
|
ack.source_id = data->cfg.id;
|
|
ack.destination_id = p->header.source_id;
|
|
ack.type = PACKET_TYPE_ACK;
|
|
ack.rx_seq = p->header.tx_seq;
|
|
ack.data_size = 0;
|
|
|
|
// Set the packet.
|
|
PHLTransmitPacket(data, (PHPacketHandle)&ack);
|
|
|
|
return 1;
|
|
}
|