Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions asyn/drvAsynSerial/drvAsynSerialPort.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ getOption(void *drvPvt, asynUser *pasynUser,
l = epicsSnprintf(val, valSize, "%c", (tty->termios.c_iflag & IXOFF) ? 'Y' : 'N');
#endif
}
#ifndef vxWorks
else if (epicsStrCaseCmp(key, "break") == 0) {
/* request serial line break status */
l = epicsSnprintf(val, valSize, "off");
}
#endif
#ifdef ASYN_RS485_SUPPORTED
else if (epicsStrCaseCmp(key, "rs485_enable") == 0) {
l = epicsSnprintf(val, valSize, "%c", (tty->rs485.flags & SER_RS485_ENABLED) ? 'Y' : 'N');
Expand Down Expand Up @@ -497,6 +503,30 @@ setOption(void *drvPvt, asynUser *pasynUser, const char *key, const char *val)
}
#endif
}
#ifndef vxWorks
else if (epicsStrCaseCmp(key, "break") == 0) {
/* signal serial line break */
unsigned break_len;
if (*val == '\0' || epicsStrCaseCmp(val, "on") == 0) break_len = 0;
else if (epicsStrCaseCmp(val, "off") == 0) return asynSuccess;
else {
if (sscanf(val, "%u", &break_len) != 1) {
epicsSnprintf(pasynUser->errorMessage,
pasynUser->errorMessageSize, "Bad number");
return asynError;
}
}
tcdrain(tty->fd); /* ensure all data transmitted prior to break */
if (tcsendbreak(tty->fd, break_len) < 0) {
epicsSnprintf(pasynUser->errorMessage,
pasynUser->errorMessageSize,
"%s tcsendbreak failed: %s",
tty->serialDeviceName, strerror(errno));
return asynError;
}
return asynSuccess;
}
#endif
#ifdef ASYN_RS485_SUPPORTED
else if (epicsStrCaseCmp(key, "rs485_enable") == 0) {
if (epicsStrCaseCmp(val, "Y") == 0) {
Expand Down
44 changes: 44 additions & 0 deletions asyn/drvAsynSerial/drvAsynSerialPortWin32.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ typedef struct {
double writeTimeout;
epicsTimerId timer;
volatile int timeoutFlag;
unsigned break_active;
asynInterface common;
asynInterface option;
asynInterface octet;
Expand Down Expand Up @@ -143,6 +144,10 @@ getOption(void *drvPvt, asynUser *pasynUser,
else if (epicsStrCaseCmp(key, "ixoff") == 0) {
l = epicsSnprintf(val, valSize, "%c", (tty->commConfig.dcb.fInX == TRUE) ? 'Y' : 'N');
}
else if (epicsStrCaseCmp(key, "break") == 0) {
/* request serial line break status */
l = epicsSnprintf(val, valSize, "%s", tty->break_active ? "on" : "off");
}
else {
epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
"Unsupported key \"%s\"", key);
Expand Down Expand Up @@ -294,6 +299,44 @@ setOption(void *drvPvt, asynUser *pasynUser, const char *key, const char *val)
return asynError;
}
}
else if (epicsStrCaseCmp(key, "break") == 0) {
/* signal serial line break */
unsigned on, off, len, break_len;
on = off = len = break_len = 0;
if (epicsStrCaseCmp(val, "on") == 0) /* switch break condition on */
on = tty->break_active ? 0 : 1;
else if (epicsStrCaseCmp(val, "off") == 0) /* switch break condition off */
off = tty->break_active ? 1 : 0;
else {
/* switch break condition on for a period of time and then off */
if (*val != '\0' && sscanf(val, "%u", &break_len) != 1) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"Bad number");
return asynError;
}
on = tty->break_active ? 0 : 1;
off = len = 1;
}
if (on) {
FlushFileBuffers(tty->commHandle); /* ensure all data transmitted prior to break */
if (SetCommBreak(tty->commHandle) == 0) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"Bad number");
return asynError;
}
tty->break_active = 1;
}
if (len) Sleep(break_len > 0 ? break_len : 250); /* wait while break is being asserted */
if (off) {
if (ClearCommBreak(tty->commHandle) == 0) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"Bad number");
return asynError;
}
tty->break_active = 0;
}
return asynSuccess;
}
else if (epicsStrCaseCmp(key, "") != 0) {
epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
"Unsupported key \"%s\"", key);
Expand Down Expand Up @@ -399,6 +442,7 @@ connectIt(void *drvPvt, asynUser *pasynUser)
}

/* setOption(tty, tty->pasynUser, "baud", "9600"); */
ClearCommBreak(tty->commHandle); /* in case there is one leftover from an ioc termination */

/*
* Turn off non-blocking mode
Expand Down
51 changes: 50 additions & 1 deletion asyn/miscellaneous/asynInterposeCom.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <epicsStdio.h>
#include <epicsString.h>
#include <epicsTypes.h>
#include <epicsThread.h>

#include "asynDriver.h"
#include "asynOctet.h"
Expand Down Expand Up @@ -50,8 +51,11 @@
#define CPO_SET_STOPSIZE 4 /* Comand port option set stop size */
#define CPO_SET_CONTROL 5 /* Comand port option set control mode */
# define CPO_CONTROL_NOFLOW 1 /* No flow control */
# define CPO_CONTROL_IXON 2 /* XON/XOFF Flow control*/
# define CPO_CONTROL_IXON 2 /* XON/XOFF Flow control*/
# define CPO_CONTROL_HWFLOW 3 /* Hardware flow control */
# define CPO_CONTROL_BREAK 4 /* request break state */
# define CPO_CONTROL_BREAK_ON 5 /* break state ON */
# define CPO_CONTROL_BREAK_OFF 6 /* break state OFF */
#define CPO_SET_LINESTATE_MASK 10 /* Comand port option set linestate mask */
#define CPO_SET_MODEMSTATE_MASK 11 /* Comand port option set modemstate mask */
#define CPO_SERVER_NOTIFY_LINESTATE 106
Expand All @@ -75,6 +79,7 @@ typedef struct interposePvt {
int bits;
int stop;
int flow;
int break_active;

char *xBuf; /* Buffer for transmit IAC stuffing */
size_t xBufCapacity;
Expand Down Expand Up @@ -597,6 +602,45 @@ setOption(void *ppvt, asynUser *pasynUser, const char *key, const char *val)
printf("XON/XOFF not set.\n");
}
}
else if (epicsStrCaseCmp(key, "break") == 0) {
/* signal serial line break */
unsigned on, off, len, break_len;
on = off = len = break_len = 0;
if (epicsStrCaseCmp(val, "on") == 0) /* switch break condition on */
on = pinterposePvt->break_active ? 0 : 1;
else if (epicsStrCaseCmp(val, "off") == 0) /* switch break condition off */
off = pinterposePvt->break_active ? 1 : 0;
else {
/* switch break condition on for a period of time and then off */
if (*val != '\0' && sscanf(val, "%u", &break_len) != 1) {
epicsSnprintf(pasynUser->errorMessage,
pasynUser->errorMessageSize, "Bad number");
return asynError;
}
on = pinterposePvt->break_active ? 0 : 1;
off = len = 1;
}
if (on) {
xBuf[0] = CPO_SET_CONTROL;
xBuf[1] = CPO_CONTROL_BREAK_ON;
status = sbComPortOption(pinterposePvt, pasynUser, xBuf, 2, rBuf);
if (status != asynSuccess) return status;
pinterposePvt->break_active = (rBuf[0] == CPO_CONTROL_BREAK_ON) ? 1 : 0;
}
if (len) {
/* wait while break is being asserted */
if (!break_len) break_len = 250;
epicsThreadSleep(((double)break_len) / 1000.);
}
if (off) {
xBuf[0] = CPO_SET_CONTROL;
xBuf[1] = CPO_CONTROL_BREAK_OFF;
status = sbComPortOption(pinterposePvt, pasynUser, xBuf, 2, rBuf);
if (status != asynSuccess) return status;
pinterposePvt->break_active = (rBuf[0] == CPO_CONTROL_BREAK_ON) ? 1 : 0;
}
return asynSuccess;
}
else {
if (pinterposePvt->pasynOptionDrv) {
/* Call the setOption function in the underlying driver */
Expand Down Expand Up @@ -657,6 +701,11 @@ getOption(void *ppvt, asynUser *pasynUser, const char *key, char *val, int valSi
return asynError;
}
}
else if (epicsStrCaseCmp(key, "break") == 0) {
/* request serial line break status */
l = epicsSnprintf(val, valSize, "%s",
pinterposePvt->break_active ? "on" : "off");
}
else {
if (pinterposePvt->pasynOptionDrv) {
/* Call the getOption function in the underlying driver */
Expand Down
10 changes: 9 additions & 1 deletion docs/source/asynDriver.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3143,7 +3143,7 @@ This provides the ability to configure serial ports on terminal servers using th
RFC 2117 protocol. It is not configured from the iocsh directly, but is rather configured
automatically by the drvAsynIPPort driver if the COM protocol is specified. It supports
the same options as drvAsynSerialPort, i.e. "baud", "bits", "parity", "stop", "crtscts",
and "ixon".
"ixon" and "break".

asynInterposeDelay
~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -4227,6 +4227,8 @@ values. When a serial port connects the current values are fetched.
- msec_delay
* - rs485_delay_rts_after_send
- msec_delay
* - break
off on <numeric-device-dependend-time>

On some systems (e.g. Windows, Darwin) the driver accepts any numeric value for
the baud rate, which must, of course be supported by the system hardware. On Linux
Expand Down Expand Up @@ -4261,6 +4263,12 @@ This flag is not available on all systems, including WIN32.
The rs485 options are only supported on Linux, only kernels &ge; 2.6.35, and only
on hardware ports that support RS-485. The delay option units are integer milliseconds.

The break option should send a serial break state on supported systems (Linux,
Windows work, vxWorks does not). A numeric value should send a break for the
specified time, which is device depended (deci seconds, milli seconds, ...).
A zero value means a default time. A value "on" should set the break state on
for a unlimited time and "off" should clear the break state.

vxWorks IOC serial ports may need to be set up using hardware-specific commands.
Once this is done, the standard drvAsynSerialPortConfigure and asynSetOption commands
can be issued. For example, the following example shows the configuration procedure
Expand Down