Add XON/XOFF flow control on Serial + USB. This is enabled by default for Serial (fix #20)

This commit is contained in:
Gordon Williams 2014-09-26 16:51:01 +01:00
parent c4a52e234e
commit b9266cdf87
9 changed files with 84 additions and 4 deletions

View File

@ -2,6 +2,7 @@
Fix break inside loop inside case inside function (fix 428)
Added fs.stat and File.seek (fix #429, fix #430)
Allow use of DLE (char 16) on an empty line to turn echo off for *just that line*
Add XON/XOFF flow control on Serial + USB. This is enabled by default for Serial (fix #20)
1v70 : Make pipe remove its drain/close listeners. Stops out of memory for repeated piping.
Fix parseInt for values too large to go in an int (#406)

View File

@ -34,6 +34,25 @@ typedef struct {
TxBufferItem txBuffer[TXBUFFERMASK+1];
volatile unsigned char txHead=0, txTail=0;
typedef enum {
SDS_NONE,
SDS_XOFF_PENDING = 1,
SDS_XON_PENDING = 2,
SDS_XOFF_SENT = 4, // sending XON clears this
SDS_FLOW_CONTROL_XON_XOFF = 8, // flow control enabled
} PACKED_FLAGS JshSerialDeviceState;
JshSerialDeviceState jshSerialDeviceStates[USARTS+1];
// ----------------------------------------------------------------------------
void jshInitDevices() { // called from jshInit
int i;
jshSerialDeviceStates[0] = SDS_FLOW_CONTROL_XON_XOFF; // USB
for (i=1;i<=USARTS;i++)
jshSerialDeviceStates[i] = SDS_NONE;
}
// ----------------------------------------------------------------------------
// Queue a character for transmission
@ -78,6 +97,18 @@ void jshTransmit(IOEventFlags device, unsigned char data) {
// Try and get a character for transmission - could just return -1 if nothing
int jshGetCharToTransmit(IOEventFlags device) {
if (DEVICE_IS_USART(device)) {
JshSerialDeviceState *deviceState = &jshSerialDeviceStates[device-EV_USBSERIAL];
if ((*deviceState)&SDS_XOFF_PENDING) {
(*deviceState) = ((*deviceState)&(~SDS_XOFF_PENDING)) | SDS_XOFF_SENT;
return 19/*XOFF*/;
}
if ((*deviceState)&SDS_XON_PENDING) {
(*deviceState) = ((*deviceState)&(~(SDS_XON_PENDING|SDS_XOFF_SENT)));
return 17/*XON*/;
}
}
unsigned char ptr = txTail;
while (txHead != ptr) {
if (IOEVENTFLAGS_GETTYPE(txBuffer[ptr].flags) == device) {
@ -207,7 +238,7 @@ bool jshPopIOEventOfType(IOEventFlags eventType, IOEvent *result) {
if (IOEVENTFLAGS_GETTYPE(ioBuffer[i].flags) == eventType) {
*result = ioBuffer[i];
// work back and shift all items in out queue
unsigned char n = (unsigned char)((n+IOBUFFERMASK) & IOBUFFERMASK);
unsigned char n = (unsigned char)((i+IOBUFFERMASK) & IOBUFFERMASK);
while (n!=ioTail) {
ioBuffer[i] = ioBuffer[n];
i = n;
@ -340,7 +371,34 @@ IOEventFlags jshFromDeviceString(const char *device) {
/// Set whether the host should transmit or not
void jshSetFlowControlXON(IOEventFlags device, bool hostShouldTransmit) {
NOT_USED(device);
NOT_USED(hostShouldTransmit);
if (DEVICE_IS_USART(device)) {
JshSerialDeviceState *deviceState = &jshSerialDeviceStates[device-EV_USBSERIAL];
if ((*deviceState) & SDS_FLOW_CONTROL_XON_XOFF) {
if (hostShouldTransmit) {
if (((*deviceState)&(SDS_XOFF_SENT|SDS_XON_PENDING)) == SDS_XOFF_SENT) {
jshInterruptOff();
(*deviceState) |= SDS_XON_PENDING;
jshInterruptOn();
jshUSARTKick(device);
}
} else { // !hostShouldTransmit
if (((*deviceState)&(SDS_XOFF_SENT|SDS_XOFF_PENDING)) == 0) {
jshInterruptOff();
(*deviceState) |= SDS_XOFF_PENDING;
jshInterruptOn();
jshUSARTKick(device);
}
}
}
}
}
/// Set whether to use flow control on the given device or not
void jshSetFlowControlEnabled(IOEventFlags device, bool xOnXOff) {
if (!DEVICE_IS_USART(device)) return;
JshSerialDeviceState *deviceState = &jshSerialDeviceStates[device-EV_USBSERIAL];
if (xOnXOff)
(*deviceState) |= SDS_FLOW_CONTROL_XON_XOFF;
else
(*deviceState) &= ~SDS_FLOW_CONTROL_XON_XOFF;
}

View File

@ -17,6 +17,8 @@
#include "jsutils.h"
#include "platform_config.h"
void jshInitDevices(); // called from jshInit
typedef enum {
// device type
EV_NONE,
@ -130,4 +132,7 @@ int jshGetCharToTransmit(IOEventFlags device);
/// Set whether the host should transmit or not
void jshSetFlowControlXON(IOEventFlags device, bool hostShouldTransmit);
/// Set whether to use flow control on the given device or not
void jshSetFlowControlEnabled(IOEventFlags device, bool xOnXOff);
#endif /* JSDEVICES_H_ */

View File

@ -142,6 +142,7 @@ typedef struct {
unsigned char bytesize;
unsigned char parity;
unsigned char stopbits;
bool xOnXOff; // XON XOFF flow control?
} PACKED_FLAGS JshUSARTInfo;
static inline void jshUSARTInitInfo(JshUSARTInfo *inf) {
@ -151,6 +152,7 @@ static inline void jshUSARTInitInfo(JshUSARTInfo *inf) {
inf->bytesize = DEFAULT_BYTESIZE;
inf->parity = DEFAULT_PARITY; // PARITY_NONE = 0, PARITY_ODD = 1, PARITY_EVEN = 2 FIXME: enum?
inf->stopbits = DEFAULT_STOPBITS;
inf->xOnXOff = false;
}
/** Set up a UART, if pins are -1 they will be guessed */

View File

@ -126,7 +126,7 @@ Set this Serial port as the port for the console
"generate" : "jswrap_serial_setup",
"params" : [
["baudrate","JsVar","The baud rate - the default is 9600"],
["options","JsVar",["An optional structure containing extra information on initialising the serial port.","```{rx:pin,tx:pin,bytesize:8,parity:null/'none'/'o'/'odd'/'e'/'even',stopbits:1}```","You can find out which pins to use by looking at [your board's reference page](#boards) and searching for pins with the `UART`/`USART` markers.","Note that even after changing the RX and TX pins, if you have called setup before then the previous RX and TX pins will still be connected to the Serial port as well - until you set them to something else using digitalWrite"]]
["options","JsVar",["An optional structure containing extra information on initialising the serial port.","```{rx:pin,tx:pin,bytesize:8,parity:null/'none'/'o'/'odd'/'e'/'even',stopbits:1,flow:null/undefined/'none'/'xon'}```","You can find out which pins to use by looking at [your board's reference page](#boards) and searching for pins with the `UART`/`USART` markers.","Note that even after changing the RX and TX pins, if you have called setup before then the previous RX and TX pins will still be connected to the Serial port as well - until you set them to something else using digitalWrite"]]
]
}
Setup this Serial port with the given baud rate and options.
@ -179,6 +179,14 @@ void jswrap_serial_setup(JsVar *parent, JsVar *baud, JsVar *options) {
if (jsvIsInt(v))
inf.stopbits = (unsigned char)jsvGetInteger(v);
jsvUnLock(v);
v = jsvObjectGetChild(options, "flow", 0);
if(jsvIsUndefined(v) || jsvIsNull(v) || jsvIsStringEqual(v, "none"))
inf.xOnXOff = false;
else if(jsvIsStringEqual(v, "xon"))
inf.xOnXOff = true;
else jsExceptionHere(JSET_ERROR, "Invalid flow control: %q", v);
jsvUnLock(v);
}
jshUSARTSetup(device, &inf);

View File

@ -32,6 +32,7 @@ IOEventFlags pinToEVEXTI(Pin pin) {
// ----------------------------------------------------------------------------
void jshInit() {
jshInitDevices();
Serial.begin(DEFAULT_BAUD_RATE);
}

View File

@ -168,6 +168,7 @@ int getch()
void jshInit() {
jshInitDevices();
#ifndef __MINGW32__
if (!terminal_set) {
struct termios new_termios;

View File

@ -58,6 +58,7 @@ void mbedSerialIRQ(uint32_t id, SerialIrq event) {
// ----------------------------------------------------------------------------
// for non-blocking IO
void jshInit() {
jshInitDevices();
systemTimeWasHigh = false;
systemTimeHigh = 0;
systemTime.start();

View File

@ -970,6 +970,7 @@ static void jshResetSerial() {
}
void jshInit() {
jshInitDevices();
int i;
// reset some vars
for (i=0;i<16;i++)
@ -1954,6 +1955,8 @@ void *NO_INLINE checkPinsForDevice(JshPinFunction device, int count, Pin *pins,
void jshUSARTSetup(IOEventFlags device, JshUSARTInfo *inf) {
jshSetDeviceInitialised(device, true);
jshSetFlowControlEnabled(device, inf->xOnXOff);
if (device == EV_USBSERIAL) {
return; // eep!
}