Skip to content

Commit 67e32c8

Browse files
committed
aio: Add support for modem control signals
RTS, DTR, etc. and sending a break condition Signed-off-by: Steve Bennett <[email protected]>
1 parent 474bab9 commit 67e32c8

File tree

4 files changed

+178
-1
lines changed

4 files changed

+178
-1
lines changed

jim-aio.c

+50
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,49 @@ static int aio_cmd_tty(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19061906

19071907
return ret;
19081908
}
1909+
1910+
static int aio_cmd_ttycontrol(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1911+
{
1912+
AioFile *af = Jim_CmdPrivData(interp);
1913+
Jim_Obj *dictObjPtr;
1914+
int ret;
1915+
1916+
if (argc == 0) {
1917+
/* get the current settings as a dictionary */
1918+
dictObjPtr = Jim_GetTtyControlSettings(interp, af->fd);
1919+
if (dictObjPtr == NULL) {
1920+
JimAioSetError(interp, NULL);
1921+
return JIM_ERR;
1922+
}
1923+
Jim_SetResult(interp, dictObjPtr);
1924+
return JIM_OK;
1925+
}
1926+
1927+
if (argc > 1) {
1928+
/* Convert name value arguments to a dictionary */
1929+
dictObjPtr = Jim_NewListObj(interp, argv, argc);
1930+
}
1931+
else {
1932+
/* The settings are already given as a list */
1933+
dictObjPtr = argv[0];
1934+
}
1935+
Jim_IncrRefCount(dictObjPtr);
1936+
1937+
if (Jim_ListLength(interp, dictObjPtr) % 2) {
1938+
/* Must be a valid dictionary */
1939+
Jim_DecrRefCount(interp, dictObjPtr);
1940+
return -1;
1941+
}
1942+
1943+
ret = Jim_SetTtyControlSettings(interp, af->fd, dictObjPtr);
1944+
if (ret < 0) {
1945+
JimAioSetError(interp, NULL);
1946+
ret = JIM_ERR;
1947+
}
1948+
Jim_DecrRefCount(interp, dictObjPtr);
1949+
1950+
return ret;
1951+
}
19091952
#endif /* JIM_BOOTSTRAP */
19101953

19111954
static const jim_subcmd_type aio_command_table[] = {
@@ -2151,6 +2194,13 @@ static const jim_subcmd_type aio_command_table[] = {
21512194
-1,
21522195
/* Description: Get or set tty settings - valid only on a tty */
21532196
},
2197+
{ "ttycontrol",
2198+
"?rts 0|1? ?dtr 0|1?",
2199+
aio_cmd_ttycontrol,
2200+
0,
2201+
-1,
2202+
/* Description: Get or set tty modem control settings - valid only on a tty */
2203+
},
21542204
#endif
21552205
#endif /* JIM_BOOTSTRAP */
21562206
{ NULL }

jim-tty.c

+92
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
/* termios support is required */
99
#include <jim-tty.h>
10+
#include <sys/ioctl.h>
1011
#include <termios.h>
1112

1213
static const struct {
@@ -349,3 +350,94 @@ int Jim_SetTtySettings(Jim_Interp *interp, int fd, Jim_Obj *dictObjPtr)
349350
}
350351
return 0;
351352
}
353+
354+
Jim_Obj *Jim_GetTtyControlSettings(Jim_Interp *interp, int fd)
355+
{
356+
size_t i;
357+
Jim_Obj *listObjPtr;
358+
int status;
359+
static const struct {
360+
const char * const name;
361+
int value;
362+
} modem_signals[] = {
363+
{ "rts", TIOCM_RTS },
364+
{ "dtr", TIOCM_DTR },
365+
366+
{ "dcd", TIOCM_CAR },
367+
{ "dsr", TIOCM_DSR },
368+
{ "ring", TIOCM_RNG },
369+
{ "cts", TIOCM_CTS },
370+
};
371+
372+
if (ioctl(fd, TIOCMGET, &status) < 0) {
373+
return NULL;
374+
}
375+
376+
listObjPtr = Jim_NewListObj(interp, NULL, 0);
377+
for (i = 0; i < ARRAYSIZE(modem_signals); i++) {
378+
Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, modem_signals[i].name, -1));
379+
Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, (status & modem_signals[i].value & status) != 0));
380+
}
381+
return listObjPtr;
382+
}
383+
384+
int Jim_SetTtyControlSettings(Jim_Interp *interp, int fd, Jim_Obj *dictObjPtr)
385+
{
386+
static const char * const modem_signal_names[] = {
387+
"rts", "dtr", "break", NULL
388+
};
389+
enum { OPT_RTS, OPT_DTR, OPT_BREAK, };
390+
int len = Jim_ListLength(interp, dictObjPtr);
391+
int i;
392+
393+
int status;
394+
395+
/* Get the current status of DTR and RTS in case we aren't setting everything */
396+
if (ioctl(fd, TIOCMGET, &status) < 0) {
397+
return -1;
398+
}
399+
400+
for (i = 0; i < len; i += 2) {
401+
Jim_Obj *nameObj = Jim_ListGetIndex(interp, dictObjPtr, i);
402+
Jim_Obj *valueObj = Jim_ListGetIndex(interp, dictObjPtr, i + 1);
403+
int opt;
404+
long l;
405+
406+
if (Jim_GetEnum(interp, nameObj, modem_signal_names, &opt, "signal", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
407+
return JIM_ERR;
408+
}
409+
if (Jim_GetLong(interp, valueObj, &l) != JIM_OK) {
410+
Jim_SetResultFormatted(interp, "bad value for %#s: %#s", nameObj, valueObj);
411+
return JIM_ERR;
412+
}
413+
414+
switch (opt) {
415+
case OPT_RTS:
416+
if (l) {
417+
status |= TIOCM_RTS;
418+
}
419+
else {
420+
status &= ~TIOCM_RTS;
421+
}
422+
break;
423+
424+
case OPT_DTR:
425+
if (l) {
426+
status |= TIOCM_DTR;
427+
}
428+
else {
429+
status &= ~TIOCM_DTR;
430+
}
431+
break;
432+
433+
case OPT_BREAK:
434+
tcsendbreak(fd, l);
435+
break;
436+
}
437+
}
438+
439+
if (ioctl(fd, TIOCMSET, &status) < 0) {
440+
return -1;
441+
}
442+
return JIM_OK;
443+
}

jim-tty.h

+16
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@ Jim_Obj *Jim_GetTtySettings(Jim_Interp *interp, int fd);
2323
*/
2424
int Jim_SetTtySettings(Jim_Interp *interp, int fd, Jim_Obj *dictObjPtr);
2525

26+
/**
27+
* Return the tty modem control settings for the given file descriptor as a dictionary
28+
* with a zero reference count.
29+
*
30+
* Returns NULL and sets errno file descriptor is not a valid tty.
31+
*/
32+
Jim_Obj *Jim_GetTtyControlSettings(Jim_Interp *interp, int fd);
33+
34+
/**
35+
* Sets the tty modem control settings given in 'dictObjPtr'
36+
*
37+
* Returns JIM_OK if OK, JIM_ERR if any settings are invalid,
38+
* or -1 (and sets errno) if the file descriptor is not a valid tty.
39+
*/
40+
int Jim_SetTtyControlSettings(Jim_Interp *interp, int fd, Jim_Obj *dictObjPtr);
41+
2642
#ifdef __cplusplus
2743
}
2844
#endif

jim_tcl.txt

+20-1
Original file line numberDiff line numberDiff line change
@@ -5136,7 +5136,7 @@ This command returns an empty string.
51365136

51375137
+$handle *tty* ?settings?+::
51385138
If no arguments are given, returns a dictionary containing the tty settings for the stream.
5139-
If arguments are given, they must either be a dictionary, or +setting value \...+
5139+
If arguments are given, they must either be a dictionary, or +setting value \...+.
51405140
Abbreviations are supported for both settings and values, so the following is acceptable:
51415141
+$f tty parity e input c out raw+.
51425142
Only available on platforms that support 'termios(3)'. Supported settings are:
@@ -5179,6 +5179,25 @@ This command returns an empty string.
51795179
+*vstop* 'char'+;;
51805180
Stop character for xonoff, usually 0x13 (^S)
51815181

5182+
+$handle *ttycontrol* ?settings?+::
5183+
If no arguments are given, returns a dictionary containing the modem control signals
5184+
from the stream (must be a serial-type device). e.g. +{rts 1 dtr 1 dcd 0 dsr 0 ring 0 cts 0}+.
5185+
Note that +rts+ and +dtr+ are controlled by the local system while the other signals reflect
5186+
the remote system.
5187+
If arguments are given, they must either be a dictionary, or +setting value \...+.
5188+
Abbreviations are supported for both settings and values.
5189+
Supported settings are:
5190+
5191+
+*rts 0|1*+;;
5192+
Set the RTS (Request To Send) signal
5193+
5194+
+*dtr 0|1*+;;
5195+
Set the DTR (Data Terminal Ready) signal
5196+
5197+
+*break* 'duration'+;;
5198+
Generate a break condition. +duration+ is generally ignored but may be used
5199+
in a platform-dependent manner.
5200+
51825201
+$handle *ssl* ?*-server* 'cert ?key?'|*-sni* 'servername'?+::
51835202
Upgrades the stream to a SSL/TLS session and returns the handle.
51845203
If +-server+ is specified, either both the certificate and private key files

0 commit comments

Comments
 (0)