Minor include related compile fix. Added experimental XON/XOFF flow control. Not officially supported!

- A latency issue related to USB-to-serial converters on the Arduino
does not allow for XON/XOFF flow control to work correctly on standard
terminal programs. It seems that only specialized UI's or avoiding the
USB port all together solves this problem. However, XON/XOFF flow
control is added for advanced users only as a compile-time option. This
feature is officially *NOT* supported by grbl, but let us know of any
successes with it!
This commit is contained in:
Sonny Jeon 2012-02-25 09:06:42 -07:00
parent e9b28279db
commit d6abf10d49
3 changed files with 92 additions and 28 deletions

View File

@ -114,6 +114,14 @@
// time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays.
#define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds)
// FOR ADVANCED USERS ONLY: Toggles XON/XOFF software flow control for serial communications.
// Officially not supported due to problems involving USB-to-serial chip latency (Atmega8U2/FTDI)
// when connecting to an Arduino through the USB port. This problem has to do with having no control
// of the USB packets and causing standard terminal programs not being able to honor the XON/XOFF
// control characters on time. However, with specially programmed UI's or avoiding the USB interface
// completely, XON/XOFF flow control should work. In any case, please report any successes to grbl
// administrators!
#define ENABLE_XONXOFF 0 // Boolean. Default disabled.
// -----------------------------------------------

View File

@ -21,10 +21,11 @@
#ifndef nuts_bolts_h
#define nuts_bolts_h
#include <config.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "config.h"
#define false 0
#define true 1

View File

@ -42,6 +42,27 @@ uint8_t tx_buffer[TX_BUFFER_SIZE];
uint8_t tx_buffer_head = 0;
volatile uint8_t tx_buffer_tail = 0;
#if ENABLE_XONXOFF
#define RX_BUFFER_FULL 96 // XOFF high watermark
#define RX_BUFFER_LOW 64 // XON low watermark
#define SEND_XOFF 1
#define SEND_XON 2
#define XOFF_SENT 3
#define XON_SENT 4
#define XOFF_CHAR 0x13
#define XON_CHAR 0x11
volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable
// Returns the number of bytes in the RX buffer. This replaces a typical byte counter to prevent
// the interrupt and main programs from writing to the counter at the same time.
static uint8_t get_rx_buffer_count()
{
if (rx_buffer_head == rx_buffer_tail) { return(0); }
if (rx_buffer_head < rx_buffer_tail) { return(rx_buffer_tail-rx_buffer_head); }
return (RX_BUFFER_SIZE - (rx_buffer_head-rx_buffer_tail));
}
#endif
static void set_baud_rate(long baud) {
uint16_t UBRR0_value = ((F_CPU / 16 + baud / 2) / baud - 1);
UBRR0H = UBRR0_value >> 8;
@ -84,21 +105,33 @@ void serial_write(uint8_t data) {
}
// Data Register Empty Interrupt handler
ISR(USART_UDRE_vect) {
ISR(USART_UDRE_vect)
{
// Temporary tx_buffer_tail (to optimize for volatile)
uint8_t tail = tx_buffer_tail;
#if ENABLE_XONXOFF
switch (flow_ctrl) {
case SEND_XOFF: UDR0 = XOFF_CHAR; flow_ctrl = XOFF_SENT; break;
case SEND_XON: UDR0 = XON_CHAR; flow_ctrl = XON_SENT; break;
default:
#endif
// Send a byte from the buffer
UDR0 = tx_buffer[tail];
// Update tail position
tail ++;
tail++;
if (tail == TX_BUFFER_SIZE) { tail = 0; }
tx_buffer_tail = tail;
#if ENABLE_XONXOFF
}
#endif
// Turn off Data Register Empty Interrupt to stop tx-streaming if this concludes the transfer
if (tail == tx_buffer_head) { UCSR0B &= ~(1 << UDRIE0); }
tx_buffer_tail = tail;
}
uint8_t serial_read()
@ -109,6 +142,14 @@ uint8_t serial_read()
uint8_t data = rx_buffer[rx_buffer_tail];
rx_buffer_tail++;
if (rx_buffer_tail == RX_BUFFER_SIZE) { rx_buffer_tail = 0; }
#if ENABLE_XONXOFF
if ((get_rx_buffer_count() < RX_BUFFER_LOW) && flow_ctrl != XON_SENT) {
flow_ctrl = SEND_XON;
UCSR0B |= (1 << UDRIE0); // Force TX
}
#endif
return data;
}
}
@ -116,11 +157,8 @@ uint8_t serial_read()
ISR(USART_RX_vect)
{
uint8_t data = UDR0;
uint8_t next_head = rx_buffer_head + 1;
if (next_head == RX_BUFFER_SIZE) { next_head = 0; }
uint8_t next_head;
// Write data to buffer unless it is full.
if (next_head != rx_buffer_tail) {
// Pick off runtime command characters directly from the serial stream. These characters are
// not passed into the buffer, but these set system state flag bits for runtime execution.
switch (data) {
@ -135,9 +173,22 @@ ISR(USART_RX_vect)
}
sys.execute |= EXEC_RESET; // Set as true
break;
default : // Write character to buffer
default: // Write character to buffer
next_head = rx_buffer_head + 1;
if (next_head == RX_BUFFER_SIZE) { next_head = 0; }
// Write data to buffer unless it is full.
if (next_head != rx_buffer_tail) {
rx_buffer[rx_buffer_head] = data;
rx_buffer_head = next_head;
#if ENABLE_XONXOFF
if ((get_rx_buffer_count() >= RX_BUFFER_FULL) && flow_ctrl != XOFF_SENT) {
flow_ctrl = SEND_XOFF;
UCSR0B |= (1 << UDRIE0); // Force TX
}
#endif
}
}
}
@ -145,4 +196,8 @@ ISR(USART_RX_vect)
void serial_reset_read_buffer()
{
rx_buffer_tail = rx_buffer_head;
#if ENABLE_XONXOFF
flow_ctrl = XON_SENT;
#endif
}