2014-02-03 00:19:58 +00:00
/* Teensyduino Core Library
* http : //www.pjrc.com/teensy/
* Copyright ( c ) 2013 PJRC . COM , LLC .
2016-05-31 07:19:45 +00:00
* Modified by Jacob Alexander 2013 - 2016
2014-02-03 00:19:58 +00:00
*
* Permission is hereby granted , free of charge , to any person obtaining
* a copy of this software and associated documentation files ( the
* " Software " ) , to deal in the Software without restriction , including
* without limitation the rights to use , copy , modify , merge , publish ,
* distribute , sublicense , and / or sell copies of the Software , and to
* permit persons to whom the Software is furnished to do so , subject to
* the following conditions :
*
2014-06-26 07:54:39 +00:00
* 1. The above copyright notice and this permission notice shall be
2014-02-03 00:19:58 +00:00
* included in all copies or substantial portions of the Software .
*
2014-06-26 07:54:39 +00:00
* 2. If the Software is incorporated into a build system that allows
2014-02-03 00:19:58 +00:00
* selection among a list of target devices , then similar target
* devices manufactured by PJRC . COM must be included in the list of
* target devices and selectable in the same manner .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
2016-05-31 07:19:45 +00:00
# include <kll_defs.h>
# if enableVirtualSerialPort_define == 1
2014-09-28 23:44:57 +00:00
// ----- Includes -----
// Compiler Includes
# include <string.h> // For memcpy
// Project Includes
# include <Lib/OutputLib.h>
// Local Includes
2013-01-27 06:47:52 +00:00
# include "usb_dev.h"
# include "usb_serial.h"
2014-09-28 23:44:57 +00:00
// ----- Defines -----
2013-01-27 06:47:52 +00:00
2015-03-09 01:40:01 +00:00
# define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */
2013-01-27 06:47:52 +00:00
2014-09-28 23:44:57 +00:00
// Maximum number of transmit packets to queue so we don't starve other endpoints for memory
# define TX_PACKET_LIMIT 8
// When the PC isn't listening, how long do we wait before discarding data? If this is
// too short, we risk losing data during the stalls that are common with ordinary desktop
// software. If it's too long, we stall the user's program when no software is running.
# define TX_TIMEOUT_MSEC 70
# if F_CPU == 96000000
2015-04-27 07:57:34 +00:00
# define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596)
# elif F_CPU == 72000000
# define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512) // XXX Correct?
2014-09-28 23:44:57 +00:00
# elif F_CPU == 48000000
2015-04-27 07:57:34 +00:00
# define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428)
2014-09-28 23:44:57 +00:00
# elif F_CPU == 24000000
2015-04-27 07:57:34 +00:00
# define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262)
2014-09-28 23:44:57 +00:00
# endif
// ----- Variables -----
2016-05-31 07:19:45 +00:00
// Serial port settings (baud rate, control signals, etc) set by the host
// These are *ignored*, except to return back to the host if requested
volatile USBCDCLineCoding usb_cdc_line_coding = {
115200 ,
0 ,
0 ,
8 ,
} ;
2014-09-28 23:44:57 +00:00
volatile uint8_t usb_cdc_line_rtsdtr = 0 ;
volatile uint8_t usb_cdc_transmit_flush_timer = 0 ;
static usb_packet_t * rx_packet = NULL ;
static usb_packet_t * tx_packet = NULL ;
static volatile uint8_t tx_noautoflush = 0 ;
// When we've suffered the transmit timeout, don't wait again until the computer
// begins accepting data. If no software is running to receive, we'll just discard
// data as rapidly as Serial.print() can generate it, until there's something to
// actually receive it.
static uint8_t transmit_previous_timeout = 0 ;
// ----- Functions -----
2013-01-27 06:47:52 +00:00
// get the next character, or -1 if nothing received
2014-09-28 23:44:57 +00:00
int usb_serial_getchar ( )
2013-01-27 06:47:52 +00:00
{
unsigned int i ;
int c ;
2014-09-28 23:44:57 +00:00
if ( ! rx_packet )
{
if ( ! usb_configuration )
return - 1 ;
rx_packet = usb_rx ( CDC_RX_ENDPOINT ) ;
if ( ! rx_packet )
return - 1 ;
2014-02-03 00:19:58 +00:00
}
2013-01-27 06:47:52 +00:00
i = rx_packet - > index ;
c = rx_packet - > buf [ i + + ] ;
2014-09-28 23:44:57 +00:00
if ( i > = rx_packet - > len )
{
usb_free ( rx_packet ) ;
2013-01-27 06:47:52 +00:00
rx_packet = NULL ;
2014-09-28 23:44:57 +00:00
}
else
{
2013-01-27 06:47:52 +00:00
rx_packet - > index = i ;
}
return c ;
}
// peek at the next character, or -1 if nothing received
2014-09-28 23:44:57 +00:00
int usb_serial_peekchar ( )
2013-01-27 06:47:52 +00:00
{
2014-09-28 23:44:57 +00:00
if ( ! rx_packet )
{
if ( ! usb_configuration )
return - 1 ;
rx_packet = usb_rx ( CDC_RX_ENDPOINT ) ;
if ( ! rx_packet )
return - 1 ;
2014-02-03 00:19:58 +00:00
}
2014-09-28 23:44:57 +00:00
if ( ! rx_packet )
return - 1 ;
return rx_packet - > buf [ rx_packet - > index ] ;
2013-01-27 06:47:52 +00:00
}
// number of bytes available in the receive buffer
2014-09-28 23:44:57 +00:00
int usb_serial_available ( )
2013-01-27 06:47:52 +00:00
{
2014-09-28 23:44:57 +00:00
int count = usb_rx_byte_count ( CDC_RX_ENDPOINT ) ;
if ( rx_packet )
count + = rx_packet - > len - rx_packet - > index ;
2014-02-03 00:19:58 +00:00
return count ;
}
// read a block of bytes to a buffer
2014-09-28 23:44:57 +00:00
int usb_serial_read ( void * buffer , uint32_t size )
2014-02-03 00:19:58 +00:00
{
uint8_t * p = ( uint8_t * ) buffer ;
uint32_t qty , count = 0 ;
2013-01-27 06:47:52 +00:00
2014-09-28 23:44:57 +00:00
while ( size )
{
if ( ! usb_configuration )
break ;
if ( ! rx_packet )
{
2014-02-03 00:19:58 +00:00
rx :
2014-09-28 23:44:57 +00:00
rx_packet = usb_rx ( CDC_RX_ENDPOINT ) ;
if ( ! rx_packet )
break ;
if ( rx_packet - > len = = 0 )
{
usb_free ( rx_packet ) ;
goto rx ;
}
2014-02-03 00:19:58 +00:00
}
qty = rx_packet - > len - rx_packet - > index ;
2014-09-28 23:44:57 +00:00
if ( qty > size )
qty = size ;
memcpy ( p , rx_packet - > buf + rx_packet - > index , qty ) ;
2014-02-03 00:19:58 +00:00
p + = qty ;
count + = qty ;
size - = qty ;
rx_packet - > index + = qty ;
2014-09-28 23:44:57 +00:00
if ( rx_packet - > index > = rx_packet - > len )
{
usb_free ( rx_packet ) ;
2014-02-03 00:19:58 +00:00
rx_packet = NULL ;
}
2013-01-27 06:47:52 +00:00
}
return count ;
}
// discard any buffered input
2014-09-28 23:44:57 +00:00
void usb_serial_flush_input ( )
2013-01-27 06:47:52 +00:00
{
usb_packet_t * rx ;
2014-09-28 23:44:57 +00:00
if ( ! usb_configuration )
return ;
if ( rx_packet )
{
usb_free ( rx_packet ) ;
2013-01-27 06:47:52 +00:00
rx_packet = NULL ;
}
2014-09-28 23:44:57 +00:00
while ( 1 )
{
rx = usb_rx ( CDC_RX_ENDPOINT ) ;
if ( ! rx )
break ;
usb_free ( rx ) ;
2013-01-27 06:47:52 +00:00
}
}
// transmit a character. 0 returned on success, -1 on error
2014-09-28 23:44:57 +00:00
int usb_serial_putchar ( uint8_t c )
2013-01-27 06:47:52 +00:00
{
2014-09-28 23:44:57 +00:00
return usb_serial_write ( & c , 1 ) ;
2013-01-27 06:47:52 +00:00
}
2014-09-28 23:44:57 +00:00
int usb_serial_write ( const void * buffer , uint32_t size )
2013-01-27 06:47:52 +00:00
{
uint32_t len ;
uint32_t wait_count ;
const uint8_t * src = ( const uint8_t * ) buffer ;
uint8_t * dest ;
tx_noautoflush = 1 ;
2014-09-28 23:44:57 +00:00
while ( size > 0 )
{
if ( ! tx_packet )
{
2013-01-27 06:47:52 +00:00
wait_count = 0 ;
2014-09-28 23:44:57 +00:00
while ( 1 )
{
if ( ! usb_configuration )
{
2013-01-27 06:47:52 +00:00
tx_noautoflush = 0 ;
return - 1 ;
}
2014-09-28 23:44:57 +00:00
if ( usb_tx_packet_count ( CDC_TX_ENDPOINT ) < TX_PACKET_LIMIT )
{
2013-01-27 06:47:52 +00:00
tx_noautoflush = 1 ;
tx_packet = usb_malloc ( ) ;
2014-09-28 23:44:57 +00:00
if ( tx_packet )
break ;
2013-01-27 06:47:52 +00:00
tx_noautoflush = 0 ;
}
2014-09-28 23:44:57 +00:00
if ( + + wait_count > TX_TIMEOUT | | transmit_previous_timeout )
{
2013-01-27 06:47:52 +00:00
transmit_previous_timeout = 1 ;
return - 1 ;
}
yield ( ) ;
}
}
transmit_previous_timeout = 0 ;
len = CDC_TX_SIZE - tx_packet - > index ;
2014-09-28 23:44:57 +00:00
if ( len > size )
len = size ;
2013-01-27 06:47:52 +00:00
dest = tx_packet - > buf + tx_packet - > index ;
tx_packet - > index + = len ;
size - = len ;
2014-09-28 23:44:57 +00:00
while ( len - - > 0 )
* dest + + = * src + + ;
if ( tx_packet - > index > = CDC_TX_SIZE )
{
2013-01-27 06:47:52 +00:00
tx_packet - > len = CDC_TX_SIZE ;
2014-09-28 23:44:57 +00:00
usb_tx ( CDC_TX_ENDPOINT , tx_packet ) ;
2013-01-27 06:47:52 +00:00
tx_packet = NULL ;
}
2014-02-03 00:19:58 +00:00
usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT ;
2013-01-27 06:47:52 +00:00
}
tx_noautoflush = 0 ;
return 0 ;
}
2014-09-28 23:44:57 +00:00
void usb_serial_flush_output ( )
2013-01-27 06:47:52 +00:00
{
2014-09-28 23:44:57 +00:00
if ( ! usb_configuration )
return ;
2014-02-03 00:19:58 +00:00
tx_noautoflush = 1 ;
2014-09-28 23:44:57 +00:00
if ( tx_packet )
{
2013-01-27 06:47:52 +00:00
usb_cdc_transmit_flush_timer = 0 ;
tx_packet - > len = tx_packet - > index ;
2014-09-28 23:44:57 +00:00
usb_tx ( CDC_TX_ENDPOINT , tx_packet ) ;
2013-01-27 06:47:52 +00:00
tx_packet = NULL ;
2014-09-28 23:44:57 +00:00
}
else
{
2014-02-03 00:19:58 +00:00
usb_packet_t * tx = usb_malloc ( ) ;
2014-09-28 23:44:57 +00:00
if ( tx )
{
2014-02-03 00:19:58 +00:00
usb_cdc_transmit_flush_timer = 0 ;
2014-09-28 23:44:57 +00:00
usb_tx ( CDC_TX_ENDPOINT , tx ) ;
}
else
{
2014-02-03 00:19:58 +00:00
usb_cdc_transmit_flush_timer = 1 ;
}
2013-01-27 06:47:52 +00:00
}
2014-02-03 00:19:58 +00:00
tx_noautoflush = 0 ;
2013-01-27 06:47:52 +00:00
}
2014-09-28 23:44:57 +00:00
void usb_serial_flush_callback ( )
2013-01-27 06:47:52 +00:00
{
2014-09-28 23:44:57 +00:00
if ( tx_noautoflush )
return ;
if ( tx_packet )
{
2014-02-03 00:19:58 +00:00
tx_packet - > len = tx_packet - > index ;
2014-09-28 23:44:57 +00:00
usb_tx ( CDC_TX_ENDPOINT , tx_packet ) ;
2014-02-03 00:19:58 +00:00
tx_packet = NULL ;
} else {
usb_packet_t * tx = usb_malloc ( ) ;
2014-09-28 23:44:57 +00:00
if ( tx )
{
usb_tx ( CDC_TX_ENDPOINT , tx ) ;
}
else
{
2014-02-03 00:19:58 +00:00
usb_cdc_transmit_flush_timer = 1 ;
}
}
2013-01-27 06:47:52 +00:00
}
2016-05-31 07:19:45 +00:00
# endif