1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-29 07:24:13 +01:00
LibrePilot/flight/PiOS/STM32F10x/pios_usb_com.c

503 lines
17 KiB
C
Raw Normal View History

/**
******************************************************************************
*
* @file pios_sys.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2009.
* @brief Sets up basic system hardware, functions are called from Main.
* @see The GNU Public License (GPL) Version 3
* @defgroup PIOS_SYS System Functions
* @{
*
*****************************************************************************/
/*
* 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
*/
/* Project Includes */
#include "pios.h"
#include <usb_lib.h>
#if !defined(PIOS_DONT_USE_USB_COM)
/////////////////////////////////////////////////////////////////////////////
// Local Defines
/////////////////////////////////////////////////////////////////////////////
#define SEND_ENCAPSULATED_COMMAND 0x00
#define GET_ENCAPSULATED_RESPONSE 0x01
#define SET_COMM_FEATURE 0x02
#define GET_COMM_FEATURE 0x03
#define CLEAR_COMM_FEATURE 0x04
#define SET_LINE_CODING 0x20
#define GET_LINE_CODING 0x21
#define SET_CONTROL_LINE_STATE 0x22
#define SEND_BREAK 0x23
/////////////////////////////////////////////////////////////////////////////
// Local Types
/////////////////////////////////////////////////////////////////////////////
typedef struct
{
u32 bitrate;
u8 format;
u8 paritytype;
u8 datatype;
} LINE_CODING;
/////////////////////////////////////////////////////////////////////////////
// Local prototypes
/////////////////////////////////////////////////////////////////////////////
void PIOS_USB_COM_TxBufferHandler(void);
void PIOS_USB_COM_RxBufferHandler(void);
/////////////////////////////////////////////////////////////////////////////
// Local Variables
/////////////////////////////////////////////////////////////////////////////
// rx/tx status
static volatile u8 rx_buffer_new_data_ctr;
static volatile u8 rx_buffer_ix;
static volatile u8 tx_buffer_busy;
// transfer possible?
static u8 transfer_possible = 0;
// COM Requests
u8 Request = 0;
// Default linecoding
LINE_CODING linecoding = {
115200, /* baud rate*/
0x00, /* stop bits-1*/
0x00, /* parity - none*/
0x08 /* no. of bits 8*/
};
/////////////////////////////////////////////////////////////////////////////
//! Initializes USB COM layer
//! \param[in] mode currently only mode 0 supported
//! \return < 0 if initialisation failed
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_Init(u32 mode)
{
// currently only mode 0 supported
if( mode != 0 )
return -1; // unsupported mode
return 0; // no error
}
/////////////////////////////////////////////////////////////////////////////
//! This function is called by the USB driver on cable connection/disconnection
//! \param[in] connected connection status (1 if connected)
//! \return < 0 on errors
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_ChangeConnectionState(u8 connected)
{
// in all cases: re-initialize USB COM driver
if( connected ) {
transfer_possible = 1;
rx_buffer_new_data_ctr = 0;
SetEPRxValid(ENDP3);
tx_buffer_busy = 0; // buffer not busy anymore
} else {
// cable disconnected: disable transfers
transfer_possible = 0;
rx_buffer_new_data_ctr = 0;
tx_buffer_busy = 1; // buffer busy
}
return 0; // no error
}
/////////////////////////////////////////////////////////////////////////////
//! This function returns the connection status of the USB COM interface
//! \return 1: interface available
//! \return 0: interface not available
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_CheckAvailable(void)
{
return transfer_possible ? 1 : 0;
}
/////////////////////////////////////////////////////////////////////////////
//! Returns number of free bytes in receive buffer
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \return number of free bytes
//! \return 0 if usb_com not available
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_RxBufferFree(u8 usb_com)
{
#if PIOS_USB_COM_NUM == 0
return 0; // no USB_COM available
#else
if( usb_com >= PIOS_USB_COM_NUM )
return 0;
else
return PIOS_USB_COM_DATA_OUT_SIZE-rx_buffer_new_data_ctr;
#endif
}
/////////////////////////////////////////////////////////////////////////////
//! Returns number of used bytes in receive buffer
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \return number of used bytes
//! \return 0 if usb_com not available
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_RxBufferUsed(u8 usb_com)
{
#if PIOS_USB_COM_NUM == 0
return 0; // no USB_COM available
#else
if( usb_com >= PIOS_USB_COM_NUM )
return 0;
else
return rx_buffer_new_data_ctr;
#endif
}
/////////////////////////////////////////////////////////////////////////////
//! Gets a byte from the receive buffer
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \return -1 if USB_COM not available
//! \return -2 if no new byte available
//! \return >= 0: received byte
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_RxBufferGet(u8 usb_com)
{
#if PIOS_USB_COM_NUM == 0
return -1; // no USB_COM available
#else
if( usb_com >= PIOS_USB_COM_NUM )
return -1; // USB_COM not available
if( !rx_buffer_new_data_ctr )
return -2; // nothing new in buffer
// get byte - this operation should be atomic!
// PIOS_IRQ_Disable();
// TODO: access buffer directly, so that we don't need to copy into temporary buffer
u8 buffer_out[PIOS_USB_COM_DATA_OUT_SIZE];
PMAToUserBufferCopy(buffer_out, PIOS_USB_ENDP3_RXADDR, GetEPRxCount(ENDP3));
u8 b = buffer_out[rx_buffer_ix++];
if( !--rx_buffer_new_data_ctr )
SetEPRxValid(ENDP3);
// PIOS_IRQ_Enable();
return b; // return received byte
#endif
}
/////////////////////////////////////////////////////////////////////////////
//! Returns the next byte of the receive buffer without taking it
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \return -1 if USB_COM not available
//! \return -2 if no new byte available
//! \return >= 0: received byte
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_RxBufferPeek(u8 usb_com)
{
#if PIOS_USB_COM_NUM == 0
return -1; // no USB_COM available
#else
if( usb_com >= PIOS_USB_COM_NUM )
return -1; // USB_COM not available
if( !rx_buffer_new_data_ctr )
return -2; // nothing new in buffer
// get byte - this operation should be atomic!
// PIOS_IRQ_Disable();
// TODO: access buffer directly, so that we don't need to copy into temporary buffer
u8 buffer_out[PIOS_USB_COM_DATA_OUT_SIZE];
PMAToUserBufferCopy(buffer_out, PIOS_USB_ENDP3_RXADDR, GetEPRxCount(ENDP3));
u8 b = buffer_out[rx_buffer_ix];
// PIOS_IRQ_Enable();
return b; // return received byte
#endif
}
/////////////////////////////////////////////////////////////////////////////
//! returns number of free bytes in transmit buffer
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \return number of free bytes
//! \return 0 if usb_com not available
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_TxBufferFree(u8 usb_com)
{
#if PIOS_USB_COM_NUM == 0
return 0; // no USB_COM available
#else
if( usb_com >= PIOS_USB_COM_NUM )
return 0;
else
return tx_buffer_busy ? 0 : PIOS_USB_COM_DATA_IN_SIZE;
#endif
}
/////////////////////////////////////////////////////////////////////////////
//! Returns number of used bytes in transmit buffer
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \return number of used bytes
//! \return 0 if usb_com not available
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_TxBufferUsed(u8 usb_com)
{
#if PIOS_USB_COM_NUM == 0
return 0; // no USB_COM available
#else
if( usb_com >= PIOS_USB_COM_NUM )
return 0;
else
return tx_buffer_busy ? PIOS_USB_COM_DATA_IN_SIZE : 0;
#endif
}
/////////////////////////////////////////////////////////////////////////////
//! puts more than one byte onto the transmit buffer (used for atomic sends)
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \param[in] *buffer pointer to buffer which should be transmitted
//! \param[in] len number of bytes which should be transmitted
//! \return 0 if no error
//! \return -1 if USB_COM not available
//! \return -2 if buffer full or cannot get all requested bytes (retry)
//! \return -3 if USB_COM not supported by PIOS_USB_COM_TxBufferPut Routine
//! \return -4 if too many bytes should be sent
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_TxBufferPutMoreNonBlocking(u8 usb_com, u8 *buffer, u16 len)
{
#if PIOS_USB_COM_NUM == 0
return -1; // no USB_COM available
#else
if( usb_com >= PIOS_USB_COM_NUM )
return -1; // USB_COM not available
if( len > PIOS_USB_COM_DATA_IN_SIZE )
return -4; // cannot get all requested bytes
if( tx_buffer_busy )
return -2; // buffer full (retry)
// copy bytes to be transmitted into transmit buffer
UserToPMABufferCopy(buffer, PIOS_USB_ENDP4_TXADDR, len);
// send buffer
tx_buffer_busy = 1;
SetEPTxCount(ENDP4, len);
SetEPTxValid(ENDP4);
return 0; // no error
#endif
}
/////////////////////////////////////////////////////////////////////////////
//! puts more than one byte onto the transmit buffer (used for atomic sends)<BR>
//! (blocking function)
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \param[in] *buffer pointer to buffer which should be transmitted
//! \param[in] len number of bytes which should be transmitted
//! \return 0 if no error
//! \return -1 if USB_COM not available
//! \return -3 if USB_COM not supported by PIOS_USB_COM_TxBufferPut Routine
//! \return -4 if too many bytes should be sent
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_TxBufferPutMore(u8 usb_com, u8 *buffer, u16 len)
{
s32 error;
while( (error=PIOS_USB_COM_TxBufferPutMoreNonBlocking(usb_com, buffer, len)) == -2 );
return error;
}
/////////////////////////////////////////////////////////////////////////////
//! puts a byte onto the transmit buffer
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \param[in] b byte which should be put into Tx buffer
//! \return 0 if no error
//! \return -1 if USB_COM not available
//! \return -2 if buffer full (retry)
//! \return -3 if USB_COM not supported by PIOS_USB_COM_TxBufferPut Routine
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_TxBufferPut_NonBlocking(u8 usb_com, u8 b)
{
// for more comfortable usage...
// -> just forward to PIOS_USB_COM_TxBufferPutMore
return PIOS_USB_COM_TxBufferPutMoreNonBlocking(usb_com, &b, 1);
}
/////////////////////////////////////////////////////////////////////////////
//! puts a byte onto the transmit buffer<BR>
//! (blocking function)
//! \param[in] usb_com USB_COM number (not supported yet, should always be 0)
//! \param[in] b byte which should be put into Tx buffer
//! \return 0 if no error
//! \return -1 if USB_COM not available
//! \return -3 if USB_COM not supported by PIOS_USB_COM_TxBufferPut Routine
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
s32 PIOS_USB_COM_TxBufferPut(u8 usb_com, u8 b)
{
s32 error;
while( (error=PIOS_USB_COM_TxBufferPutMoreNonBlocking(usb_com, &b, 1)) == -2 );
return error;
}
/////////////////////////////////////////////////////////////////////////////
//! Called by STM32 USB driver to check for IN streams
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
void PIOS_USB_COM_EP4_IN_Callback(void)
{
// package has been sent
tx_buffer_busy = 0;
}
/////////////////////////////////////////////////////////////////////////////
//! Called by STM32 USB driver to check for OUT streams
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
void PIOS_USB_COM_EP3_OUT_Callback(void)
{
// new data has been received - notify this
rx_buffer_new_data_ctr = GetEPRxCount(ENDP3);
rx_buffer_ix = 0;
}
/////////////////////////////////////////////////////////////////////////////
//! PIOS_USB callback functions (forwarded from STM32 USB driver)
//! \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
/////////////////////////////////////////////////////////////////////////////
void PIOS_USB_COM_CB_StatusIn(void)
{
if( Request == SET_LINE_CODING ) {
// configure UART here...
Request = 0;
}
}
// handles the data class specific requests
static u8 *Virtual_Com_Port_GetLineCoding(u16 Length) {
if( Length == 0 ) {
pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding);
return NULL;
}
return(u8 *)&linecoding;
}
u8 *Virtual_Com_Port_SetLineCoding(u16 Length)
{
if( Length == 0 ) {
pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding);
return NULL;
}
return(u8 *)&linecoding;
}
s32 PIOS_USB_COM_CB_Data_Setup(u8 RequestNo)
{
u8 *(*CopyRoutine)(u16) = NULL;
if( RequestNo == GET_LINE_CODING ) {
if( Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT) ) {
CopyRoutine = Virtual_Com_Port_GetLineCoding;
}
} else if( RequestNo == SET_LINE_CODING ) {
if( Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT) ) {
CopyRoutine = Virtual_Com_Port_SetLineCoding;
}
Request = SET_LINE_CODING;
}
if( CopyRoutine == NULL ) {
return USB_UNSUPPORT;
}
pInformation->Ctrl_Info.CopyData = CopyRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyRoutine)(0);
return USB_SUCCESS;
}
s32 PIOS_USB_COM_CB_NoData_Setup(u8 RequestNo)
{
if( Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT) ) {
if( RequestNo == SET_COMM_FEATURE ) {
return USB_SUCCESS;
} else if( RequestNo == SET_CONTROL_LINE_STATE ) {
return USB_SUCCESS;
}
}
return USB_UNSUPPORT;
}
#endif