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
[] = {
98 #define ARRAYSIZE(A) (sizeof(A)/sizeof(*(A)))
101 * Search the flag/name map for an entry with the given name.
102 * (Actually, just matching the first char)
103 * Returns a pointer to the entry if found, or NULL if not.
105 static const struct flag_name_map
*flag_name_to_value(const struct flag_name_map
*map
, int len
, const char *name
)
109 for (i
= 0; i
< len
; i
++) {
110 /* Only need to compare the first character since all names are unique in the first char */
111 if (*name
== *map
[i
].name
) {
119 * Search the flag/name map for an entry with the matching value.
120 * Returns the corresponding name if found, or NULL if no match.
122 static const char *flag_value_to_name(const struct flag_name_map
*map
, int len
, unsigned value
)
126 for (i
= 0; i
< len
; i
++) {
127 if (value
== map
[i
].value
) {
135 * If 'str2' is not NULL, appends 'str1' and 'str2' to the list.
136 * Otherwise does nothing.
138 static void JimListAddPair(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, const char *str1
, const char *str2
)
141 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, str1
, -1));
142 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, str2
, -1));
146 Jim_Obj
*Jim_GetTtySettings(Jim_Interp
*interp
, int fd
)
155 if (tcgetattr(fd
, &tio
) < 0) {
159 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
161 p
= flag_value_to_name(parity_map
, ARRAYSIZE(parity_map
), tio
.c_cflag
& (PARENB
| PARODD
));
162 JimListAddPair(interp
, listObjPtr
, "parity", p
);
163 p
= flag_value_to_name(data_size_map
, ARRAYSIZE(data_size_map
), tio
.c_cflag
& CSIZE
);
164 JimListAddPair(interp
, listObjPtr
, "data", p
);
165 p
= flag_value_to_name(stop_size_map
, ARRAYSIZE(stop_size_map
), tio
.c_cflag
& CSTOPB
);
166 JimListAddPair(interp
, listObjPtr
, "stop", p
);
167 if (tio
.c_iflag
& (IXON
| IXOFF
)) {
170 else if (tio
.c_cflag
& CRTSCTS
) {
176 JimListAddPair(interp
, listObjPtr
, "handshake", p
);
177 p
= flag_value_to_name(input_map
, ARRAYSIZE(input_map
), tio
.c_lflag
& ICANON
);
178 JimListAddPair(interp
, listObjPtr
, "input", p
);
179 p
= flag_value_to_name(output_map
, ARRAYSIZE(output_map
), tio
.c_oflag
& OPOST
);
180 JimListAddPair(interp
, listObjPtr
, "output", p
);
182 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, "vmin", -1));
183 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, tio
.c_cc
[VMIN
]));
184 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, "vtime", -1));
185 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, tio
.c_cc
[VTIME
]));
187 speed
= cfgetispeed(&tio
);
189 for (i
= 0; i
< sizeof(baudtable
) / sizeof(*baudtable
); i
++) {
190 if (baudtable
[i
].speed
== speed
) {
191 baud
= baudtable
[i
].baud
;
195 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, "baud", -1));
196 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, baud
));
201 int Jim_SetTtySettings(Jim_Interp
*interp
, int fd
, Jim_Obj
*dictObjPtr
)
203 int len
= Jim_ListLength(interp
, dictObjPtr
);
208 if (tcgetattr(fd
, &tio
) < 0) {
212 for (i
= 0; i
< len
; i
+= 2) {
213 Jim_Obj
*nameObj
= Jim_ListGetIndex(interp
, dictObjPtr
, i
);
214 Jim_Obj
*valueObj
= Jim_ListGetIndex(interp
, dictObjPtr
, i
+ 1);
216 const struct flag_name_map
*p
;
220 if (Jim_GetEnum(interp
, nameObj
, tty_settings_names
, &opt
, "setting", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
226 if (Jim_GetLong(interp
, valueObj
, &l
) != JIM_OK
) {
229 for (j
= 0; j
< ARRAYSIZE(baudtable
); j
++) {
230 if (baudtable
[j
].baud
== l
) {
234 if (j
== ARRAYSIZE(baudtable
)) {
237 cfsetospeed(&tio
, baudtable
[j
].speed
);
238 cfsetispeed(&tio
, baudtable
[j
].speed
);
242 p
= flag_name_to_value(parity_map
, ARRAYSIZE(parity_map
), Jim_String(valueObj
));
245 Jim_SetResultFormatted(interp
, "bad value for %#s: %#s", nameObj
, valueObj
);
248 tio
.c_cflag
&= ~(PARENB
| PARODD
);
249 tio
.c_cflag
|= p
->value
;
253 p
= flag_name_to_value(stop_size_map
, ARRAYSIZE(stop_size_map
), Jim_String(valueObj
));
257 tio
.c_cflag
&= ~CSTOPB
;
258 tio
.c_cflag
|= p
->value
;
262 p
= flag_name_to_value(data_size_map
, ARRAYSIZE(data_size_map
), Jim_String(valueObj
));
266 tio
.c_cflag
&= ~CSIZE
;
267 tio
.c_cflag
|= p
->value
;
271 tio
.c_iflag
&= ~(IXON
| IXOFF
);
272 tio
.c_cflag
&= ~(CRTSCTS
);
273 if (Jim_CompareStringImmediate(interp
, valueObj
, "xonxoff")) {
274 tio
.c_iflag
|= (IXON
| IXOFF
);
276 else if (Jim_CompareStringImmediate(interp
, valueObj
, "rtscts")) {
277 tio
.c_cflag
|= CRTSCTS
;
279 else if (!Jim_CompareStringImmediate(interp
, valueObj
, "none")) {
285 if (Jim_GetLong(interp
, valueObj
, &l
) != JIM_OK
) {
292 if (Jim_GetLong(interp
, valueObj
, &l
) != JIM_OK
) {
299 p
= flag_name_to_value(output_map
, ARRAYSIZE(output_map
), Jim_String(valueObj
));
303 tio
.c_oflag
&= ~OPOST
;
304 tio
.c_oflag
|= p
->value
;
308 p
= flag_name_to_value(input_map
, ARRAYSIZE(input_map
), Jim_String(valueObj
));
313 tio
.c_lflag
|= (ECHO
| ECHOE
| ECHOK
| ECHONL
| ICANON
| IEXTEN
| ISIG
| NOFLSH
| TOSTOP
);
314 tio
.c_iflag
|= ICRNL
;
317 tio
.c_lflag
&= ~(ECHO
| ECHOE
| ECHOK
| ECHONL
| ICANON
| IEXTEN
| ISIG
| NOFLSH
| TOSTOP
);
318 tio
.c_iflag
&= ~ICRNL
;
325 if (tcsetattr(fd
, TCSAFLUSH
, &tio
) < 0) {