@ -21,11 +21,12 @@
*/
/**
Hardware Serial. cpp - Hardware serial library for Wiring
Marlin Serial. cpp - Hardware serial library for Wiring
Copyright ( c ) 2006 Nicholas Zambetti . All right reserved .
Modified 23 November 2006 by David A . Mellis
Modified 28 September 2010 by Mark Sproul
Modified 14 February 2016 by Andreas Hardtung ( added tx buffer )
*/
# include "Marlin.h"
@ -38,8 +39,13 @@
# if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)
# if UART_PRESENT(SERIAL_PORT)
ring_buffer rx_buffer = { { 0 } , 0 , 0 } ;
ring_buffer_r rx_buffer = { { 0 } , 0 , 0 } ;
# if TX_BUFFER_SIZE > 0
ring_buffer_t tx_buffer = { { 0 } , 0 , 0 } ;
static bool _written ;
# endif
# endif
FORCE_INLINE void store_char ( unsigned char c ) {
CRITICAL_SECTION_START ;
@ -61,12 +67,38 @@ FORCE_INLINE void store_char(unsigned char c) {
# endif
}
# if TX_BUFFER_SIZE > 0
FORCE_INLINE void _tx_udr_empty_irq ( void )
{
// If interrupts are enabled, there must be more data in the output
// buffer. Send the next byte
uint8_t t = tx_buffer . tail ;
uint8_t c = tx_buffer . buffer [ t ] ;
tx_buffer . tail = ( t + 1 ) & ( TX_BUFFER_SIZE - 1 ) ;
M_UDRx = c ;
// clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
SBI ( M_UCSRxA , M_TXCx ) ;
if ( tx_buffer . head = = tx_buffer . tail ) {
// Buffer empty, so disable interrupts
CBI ( M_UCSRxB , M_UDRIEx ) ;
}
}
# if defined(M_USARTx_UDRE_vect)
ISR ( M_USARTx_UDRE_vect ) {
_tx_udr_empty_irq ( ) ;
}
# endif
# endif
//#elif defined(SIG_USART_RECV)
# if defined(M_USARTx_RX_vect)
// fixed by Mark Sproul this is on the 644/644p
//SIGNAL(SIG_USART_RECV)
SIGNAL ( M_USARTx_RX_vect ) {
ISR ( M_USARTx_RX_vect ) {
unsigned char c = M_UDRx ;
store_char ( c ) ;
}
@ -107,14 +139,25 @@ void MarlinSerial::begin(long baud) {
SBI ( M_UCSRxB , M_RXENx ) ;
SBI ( M_UCSRxB , M_TXENx ) ;
SBI ( M_UCSRxB , M_RXCIEx ) ;
# if TX_BUFFER_SIZE > 0
CBI ( M_UCSRxB , M_UDRIEx ) ;
_written = false ;
# endif
}
void MarlinSerial : : end ( ) {
CBI ( M_UCSRxB , M_RXENx ) ;
CBI ( M_UCSRxB , M_TXENx ) ;
CBI ( M_UCSRxB , M_RXCIEx ) ;
CBI ( M_UCSRxB , M_UDRIEx ) ;
}
void MarlinSerial : : checkRx ( void ) {
if ( TEST ( M_UCSRxA , M_RXCx ) ) {
uint8_t c = M_UDRx ;
store_char ( c ) ;
}
}
int MarlinSerial : : peek ( void ) {
int v ;
@ -145,7 +188,16 @@ int MarlinSerial::read(void) {
return v ;
}
void MarlinSerial : : flush ( ) {
uint8_t MarlinSerial : : available ( void ) {
CRITICAL_SECTION_START ;
uint8_t h = rx_buffer . head ;
uint8_t t = rx_buffer . tail ;
CRITICAL_SECTION_END ;
return ( uint8_t ) ( RX_BUFFER_SIZE + h - t ) & ( RX_BUFFER_SIZE - 1 ) ;
}
void MarlinSerial : : flush ( void ) {
// RX
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
@ -156,6 +208,86 @@ void MarlinSerial::flush() {
CRITICAL_SECTION_END ;
}
# if TX_BUFFER_SIZE > 0
uint8_t MarlinSerial : : availableForWrite ( void ) {
CRITICAL_SECTION_START ;
uint8_t h = tx_buffer . head ;
uint8_t t = tx_buffer . tail ;
CRITICAL_SECTION_END ;
return ( uint8_t ) ( TX_BUFFER_SIZE + h - t ) & ( TX_BUFFER_SIZE - 1 ) ;
}
void MarlinSerial : : write ( uint8_t c ) {
_written = true ;
CRITICAL_SECTION_START ;
bool emty = ( tx_buffer . head = = tx_buffer . tail ) ;
CRITICAL_SECTION_END ;
// If the buffer and the data register is empty, just write the byte
// to the data register and be done. This shortcut helps
// significantly improve the effective datarate at high (>
// 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
if ( emty & & TEST ( M_UCSRxA , M_UDREx ) ) {
CRITICAL_SECTION_START ;
M_UDRx = c ;
SBI ( M_UCSRxA , M_TXCx ) ;
CRITICAL_SECTION_END ;
return ;
}
uint8_t i = ( tx_buffer . head + 1 ) & ( TX_BUFFER_SIZE - 1 ) ;
// If the output buffer is full, there's nothing for it other than to
// wait for the interrupt handler to empty it a bit
while ( i = = tx_buffer . tail ) {
if ( ! TEST ( SREG , SREG_I ) ) {
// Interrupts are disabled, so we'll have to poll the data
// register empty flag ourselves. If it is set, pretend an
// interrupt has happened and call the handler to free up
// space for us.
if ( TEST ( M_UCSRxA , M_UDREx ) )
_tx_udr_empty_irq ( ) ;
} else {
// nop, the interrupt handler will free up space for us
}
}
tx_buffer . buffer [ tx_buffer . head ] = c ;
{ CRITICAL_SECTION_START ;
tx_buffer . head = i ;
SBI ( M_UCSRxB , M_UDRIEx ) ;
CRITICAL_SECTION_END ;
}
return ;
}
void MarlinSerial : : flushTX ( void ) {
// TX
// If we have never written a byte, no need to flush. This special
// case is needed since there is no way to force the TXC (transmit
// complete) bit to 1 during initialization
if ( ! _written )
return ;
while ( TEST ( M_UCSRxB , M_UDRIEx ) | | ! TEST ( M_UCSRxA , M_TXCx ) ) {
if ( ! TEST ( SREG , SREG_I ) & & TEST ( M_UCSRxB , M_UDRIEx ) )
// Interrupts are globally disabled, but the DR empty
// interrupt should be enabled, so poll the DR empty flag to
// prevent deadlock
if ( TEST ( M_UCSRxA , M_UDREx ) )
_tx_udr_empty_irq ( ) ;
}
// If we get here, nothing is queued anymore (DRIE is disabled) and
// the hardware finished tranmission (TXC is set).
}
# else
void MarlinSerial : : write ( uint8_t c ) {
while ( ! TEST ( M_UCSRxA , M_UDREx ) )
;
M_UDRx = c ;
}
# endif
// end NEW
/// imports from print.h
@ -321,7 +453,7 @@ MarlinSerial customizedSerial;
// Currently looking for: M108, M112, M410
// If you alter the parser please don't forget to update the capabilities in Conditionals.h
void emergency_parser ( unsigned char c ) {
FORCE_INLINE void emergency_parser ( unsigned char c ) {
enum e_parser_state {
state_RESET ,