1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-30 08:24:11 +01:00
LibrePilot/flight/PipXtreme/transparent_comms.c
Stacey Sheldon 5f8760a55c com: Move buffering out of USART/HID layer and into COM layer
This allows the spektrum and sbus receiver drivers to bind
directly to the usart layer using a properly exported API
rather than overriding the interrupt handler.

Bytes are now pushed directly from the usart layer into the
com layer without any buffering.  The com layer performs all
of the buffering.

A further benefit from this approach is that we can put all
blocking/non-blocking behaviour into the COM layer and not
in the underlying drivers.

Misc related changes:
 - Remove obsolete .handler field from irq configs
 - Adapt all users of PIOS_COM_* functions to new API
 - Fixup callers of PIOS_USB_HID_Init()
2011-07-27 19:45:38 -04:00

234 lines
7.7 KiB
C

/**
******************************************************************************
*
* @file transparent_comms.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Serial communication port handling routines
* @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 <string.h>
#include "stm32f10x.h"
#include "gpio_in.h"
#include "transparent_comms.h"
#include "packet_handler.h"
#include "saved_settings.h"
#include "main.h"
#if defined(PIOS_COM_DEBUG)
#define TRANS_DEBUG
#endif
// *****************************************************************************
// local variables
uint32_t trans_previous_com_port = 0;
volatile uint16_t trans_rx_timer = 0;
volatile uint16_t trans_tx_timer = 0;
uint8_t trans_temp_buffer1[128];
uint8_t trans_temp_buffer2[128];
uint16_t trans_temp_buffer2_wr;
// *****************************************************************************
// can be called from an interrupt if you wish
void trans_1ms_tick(void)
{ // call this once every 1ms
if (trans_rx_timer < 0xffff) trans_rx_timer++;
if (trans_tx_timer < 0xffff) trans_tx_timer++;
}
// *****************************************************************************
// call this as often as possible - not from an interrupt
void trans_process(void)
{ // copy data from comm-port RX buffer to RF packet handler TX buffer, and from RF packet handler RX buffer to comm-port TX buffer
// ********************
// decide which comm-port we are using (usart or usb)
bool usb_comms = false; // TRUE if we are using the usb port for comms.
uint32_t comm_port = PIOS_COM_SERIAL; // default to using the usart comm-port
#if defined(PIOS_INCLUDE_USB_HID)
if (PIOS_USB_HID_CheckAvailable(0))
{ // USB comms is up, use the USB comm-port instead of the USART comm-port
usb_comms = true;
comm_port = PIOS_COM_TELEM_USB;
}
#endif
// ********************
// check to see if the local communication port has changed (usart/usb)
if (trans_previous_com_port == 0 && trans_previous_com_port != comm_port)
{ // the local communications port has changed .. remove any data in the buffers
trans_temp_buffer2_wr = 0;
}
else
if (usb_comms)
{ // we're using the USB for comms - keep the USART rx buffer empty
int32_t bytes = PIOS_COM_ReceiveBufferUsed(PIOS_COM_SERIAL);
while (bytes > 0)
{
uint8_t c;
PIOS_COM_ReceiveBuffer(PIOS_COM_SERIAL, &c, 1, 0);
bytes--;
}
}
trans_previous_com_port = comm_port; // remember the current comm-port we are using
// ********************
uint16_t connection_index = 0; // the RF connection we are using
// ********************
// send the data received down the comm-port to the RF packet handler TX buffer
if (saved_settings.mode == MODE_NORMAL || saved_settings.mode == MODE_STREAM_TX)
{
// free space size in the RF packet handler tx buffer
uint16_t ph_num = ph_putData_free(connection_index);
// get the number of data bytes received down the comm-port
int32_t com_num = PIOS_COM_ReceiveBufferUsed(comm_port);
// set the USART RTS handshaking line
if (!usb_comms)
{
if (ph_num < 32 || !ph_connected(connection_index))
SERIAL_RTS_CLEAR; // lower the USART RTS line - we don't have space in the buffer for anymore bytes
else
SERIAL_RTS_SET; // release the USART RTS line - we have space in the buffer for now bytes
}
else
SERIAL_RTS_SET; // release the USART RTS line
// limit number of bytes we will get to the size of the temp buffer
if (com_num > sizeof(trans_temp_buffer1))
com_num = sizeof(trans_temp_buffer1);
// limit number of bytes we will get to the size of the free space in the RF packet handler TX buffer
if (com_num > ph_num)
com_num = ph_num;
// copy data received down the comm-port into our temp buffer
register uint16_t bytes_saved = 0;
bytes_saved = PIOS_COM_ReceiveBuffer(comm_port, trans_temp_buffer1, com_num, 0);
// put the received comm-port data bytes into the RF packet handler TX buffer
if (bytes_saved > 0)
{
trans_rx_timer = 0;
ph_putData(connection_index, trans_temp_buffer1, bytes_saved);
}
}
else
{ // empty the comm-ports rx buffer
int32_t com_num = PIOS_COM_ReceiveBufferUsed(comm_port);
while (com_num > 0) {
uint8_t c;
PIOS_COM_ReceiveBuffer(comm_port, &c, 1, 0);
com_num--;
}
}
// ********************
// send the data received via the RF link out the comm-port
if (saved_settings.mode == MODE_NORMAL || saved_settings.mode == MODE_STREAM_RX)
{
if (trans_temp_buffer2_wr < sizeof(trans_temp_buffer2))
{
// get number of data bytes received via the RF link
uint16_t ph_num = ph_getData_used(connection_index);
// limit to how much space we have in the temp buffer
if (ph_num > sizeof(trans_temp_buffer2) - trans_temp_buffer2_wr)
ph_num = sizeof(trans_temp_buffer2) - trans_temp_buffer2_wr;
if (ph_num > 0)
{ // fetch the data bytes received via the RF link and save into our temp buffer
ph_num = ph_getData(connection_index, trans_temp_buffer2 + trans_temp_buffer2_wr, ph_num);
trans_temp_buffer2_wr += ph_num;
}
}
#if (defined(PIOS_COM_DEBUG) && (PIOS_COM_DEBUG == PIOS_COM_SERIAL))
if (!usb_comms)
{ // the serial-port is being used for debugging - don't send data down it
trans_temp_buffer2_wr = 0;
trans_tx_timer = 0;
return;
}
#endif
if (trans_temp_buffer2_wr > 0)
{ // we have data in our temp buffer that needs sending out the comm-port
if (usb_comms || (!usb_comms && GPIO_IN(SERIAL_CTS_PIN)))
{ // we are OK to send the data out the comm-port
// send the data out the comm-port
int32_t res = PIOS_COM_SendBufferNonBlocking(comm_port, trans_temp_buffer2, trans_temp_buffer2_wr); // this one doesn't work properly with USB :(
if (res >= 0)
{ // data was sent out the comm-port OK .. remove the sent data from the temp buffer
trans_temp_buffer2_wr = 0;
trans_tx_timer = 0;
}
else
{ // failed to send the data out the comm-port
#if defined(TRANS_DEBUG)
DEBUG_PRINTF("PIOS_COM_SendBuffer %d %d\r\n", trans_temp_buffer2_wr, res);
#endif
if (trans_tx_timer >= 5000)
trans_temp_buffer2_wr = 0; // seems we can't send our data for at least the last 5 seconds - delete it
}
}
}
}
else
{ // empty the buffer
trans_temp_buffer2_wr = 0;
trans_tx_timer = 0;
}
// ********************
}
// *****************************************************************************
void trans_init(void)
{
trans_previous_com_port = 0;
trans_temp_buffer2_wr = 0;
trans_rx_timer = 0;
trans_tx_timer = 0;
}
// *****************************************************************************