2 * Support for tty settings using termios
4 * (c) 2016 Steve Bennett <steveb@workware.net.au>
8 /* termios support is required */
43 struct flag_name_map
{
48 static const struct flag_name_map parity_map
[] = {
51 { "odd", PARENB
| PARODD
},
53 static const struct flag_name_map data_size_map
[] = {
59 static const struct flag_name_map stop_size_map
[] = {
63 static const struct flag_name_map input_map
[] = {
67 static const struct flag_name_map output_map
[] = {
72 static const char * const tty_settings_names
[] = {
100 #define ARRAYSIZE(A) (sizeof(A)/sizeof(*(A)))
103 * Search the flag/name map for an entry with the given name.
104 * (Actually, just matching the first char)
105 * Returns a pointer to the entry if found, or NULL if not.
107 static const struct flag_name_map
*flag_name_to_value(const struct flag_name_map
*map
, int len
, const char *name
)
111 for (i
= 0; i
< len
; i
++) {
112 /* Only need to compare the first character since all names are unique in the first char */
113 if (*name
== *map
[i
].name
) {
121 * Search the flag/name map for an entry with the matching value.
122 * Returns the corresponding name if found, or NULL if no match.
124 static const char *flag_value_to_name(const struct flag_name_map
*map
, int len
, unsigned value
)
128 for (i
= 0; i
< len
; i
++) {
129 if (value
== map
[i
].value
) {
137 * If 'str2' is not NULL, appends 'str1' and 'str2' to the list.
138 * Otherwise does nothing.
140 static void JimListAddPair(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, const char *str1
, const char *str2
)
143 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, str1
, -1));
144 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, str2
, -1));
148 Jim_Obj
*Jim_GetTtySettings(Jim_Interp
*interp
, int fd
)
157 if (tcgetattr(fd
, &tio
) < 0) {
161 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
163 p
= flag_value_to_name(parity_map
, ARRAYSIZE(parity_map
), tio
.c_cflag
& (PARENB
| PARODD
));
164 JimListAddPair(interp
, listObjPtr
, "parity", p
);
165 p
= flag_value_to_name(data_size_map
, ARRAYSIZE(data_size_map
), tio
.c_cflag
& CSIZE
);
166 JimListAddPair(interp
, listObjPtr
, "data", p
);
167 p
= flag_value_to_name(stop_size_map
, ARRAYSIZE(stop_size_map
), tio
.c_cflag
& CSTOPB
);
168 JimListAddPair(interp
, listObjPtr
, "stop", p
);
169 if (tio
.c_iflag
& (IXON
| IXOFF
)) {
172 else if (tio
.c_cflag
& CRTSCTS
) {
178 JimListAddPair(interp
, listObjPtr
, "handshake", p
);
179 p
= flag_value_to_name(input_map
, ARRAYSIZE(input_map
), tio
.c_lflag
& ICANON
);
180 JimListAddPair(interp
, listObjPtr
, "input", p
);
181 p
= flag_value_to_name(output_map
, ARRAYSIZE(output_map
), tio
.c_oflag
& OPOST
);
182 JimListAddPair(interp
, listObjPtr
, "output", p
);
184 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, "vmin", -1));
185 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, tio
.c_cc
[VMIN
]));
186 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, "vtime", -1));
187 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, tio
.c_cc
[VTIME
]));
189 speed
= cfgetispeed(&tio
);
191 for (i
= 0; i
< sizeof(baudtable
) / sizeof(*baudtable
); i
++) {
192 if (baudtable
[i
].speed
== speed
) {
193 baud
= baudtable
[i
].baud
;
197 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, "baud", -1));
198 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, baud
));
203 int Jim_SetTtySettings(Jim_Interp
*interp
, int fd
, Jim_Obj
*dictObjPtr
)
205 int len
= Jim_ListLength(interp
, dictObjPtr
);
210 if (tcgetattr(fd
, &tio
) < 0) {
214 for (i
= 0; i
< len
; i
+= 2) {
215 Jim_Obj
*nameObj
= Jim_ListGetIndex(interp
, dictObjPtr
, i
);
216 Jim_Obj
*valueObj
= Jim_ListGetIndex(interp
, dictObjPtr
, i
+ 1);
218 const struct flag_name_map
*p
;
222 if (Jim_GetEnum(interp
, nameObj
, tty_settings_names
, &opt
, "setting", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
228 if (Jim_GetLong(interp
, valueObj
, &l
) != JIM_OK
) {
231 for (j
= 0; j
< ARRAYSIZE(baudtable
); j
++) {
232 if (baudtable
[j
].baud
== l
) {
236 if (j
== ARRAYSIZE(baudtable
)) {
239 cfsetospeed(&tio
, baudtable
[j
].speed
);
240 cfsetispeed(&tio
, baudtable
[j
].speed
);
244 p
= flag_name_to_value(parity_map
, ARRAYSIZE(parity_map
), Jim_String(valueObj
));
247 Jim_SetResultFormatted(interp
, "bad value for %#s: %#s", nameObj
, valueObj
);
250 tio
.c_cflag
&= ~(PARENB
| PARODD
);
251 tio
.c_cflag
|= p
->value
;
255 p
= flag_name_to_value(stop_size_map
, ARRAYSIZE(stop_size_map
), Jim_String(valueObj
));
259 tio
.c_cflag
&= ~CSTOPB
;
260 tio
.c_cflag
|= p
->value
;
264 p
= flag_name_to_value(data_size_map
, ARRAYSIZE(data_size_map
), Jim_String(valueObj
));
268 tio
.c_cflag
&= ~CSIZE
;
269 tio
.c_cflag
|= p
->value
;
273 tio
.c_iflag
&= ~(IXON
| IXOFF
);
274 tio
.c_cflag
&= ~(CRTSCTS
);
275 if (Jim_CompareStringImmediate(interp
, valueObj
, "xonxoff")) {
276 tio
.c_iflag
|= (IXON
| IXOFF
);
278 else if (Jim_CompareStringImmediate(interp
, valueObj
, "rtscts")) {
279 tio
.c_cflag
|= CRTSCTS
;
281 else if (!Jim_CompareStringImmediate(interp
, valueObj
, "none")) {
287 if (Jim_GetLong(interp
, valueObj
, &l
) != JIM_OK
) {
294 if (Jim_GetLong(interp
, valueObj
, &l
) != JIM_OK
) {
301 p
= flag_name_to_value(output_map
, ARRAYSIZE(output_map
), Jim_String(valueObj
));
305 tio
.c_oflag
&= ~OPOST
;
306 tio
.c_oflag
|= p
->value
;
310 p
= flag_name_to_value(input_map
, ARRAYSIZE(input_map
), Jim_String(valueObj
));
315 tio
.c_lflag
|= (ECHO
| ECHOE
| ECHOK
| ECHONL
| ICANON
| IEXTEN
| ISIG
| NOFLSH
| TOSTOP
);
316 tio
.c_iflag
|= ICRNL
;
319 tio
.c_lflag
&= ~(ECHO
| ECHOE
| ECHOK
| ECHONL
| ICANON
| IEXTEN
| ISIG
| NOFLSH
| TOSTOP
);
320 tio
.c_iflag
&= ~ICRNL
;
325 if (Jim_GetLong(interp
, valueObj
, &l
) != JIM_OK
) {
332 tio
.c_lflag
&= ~ECHO
;
339 if (tcsetattr(fd
, TCSAFLUSH
, &tio
) < 0) {