1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date             Author          Notes
8  * 2017-08-30       Bernard         The first version
9  * 2024-04-26       TroyMitchell    Add comments for all functions
10  */
11 
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <sys/errno.h>
16 #include "termios.h"
17 #include <rtthread.h>
18 
19 /**
20  * @brief   Gets the current attributes of a terminal device.
21  * @param   fd File descriptor of the terminal device.
22  * @param   tio Pointer to a struct termios where the attributes will be stored.
23  * @return  Upon successful completion, returns 0; otherwise, returns -1.
24  *
25  * @note    This function retrieves the current attributes of a terminal device specified by the file descriptor fd.
26  *          It uses the ioctl system call with the TCGETA command to obtain the attributes and stores them in the
27  *          struct termios pointed to by tio.
28  *          If the ioctl operation fails, the function returns -1 to indicate an error.
29  */
tcgetattr(int fd,struct termios * tio)30 int tcgetattr(int fd, struct termios *tio)
31 {
32     /* Get the current serial port settings. */
33     if (ioctl(fd, TCGETA, tio))
34         return -1;
35 
36     return 0;
37 }
38 
39 /**
40  * @brief   Sets the attributes of a terminal device.
41  * @param   fd File descriptor of the terminal device.
42  * @param   act Action to be taken for the attribute change (TCSANOW, TCSADRAIN, or TCSAFLUSH).
43  * @param   tio Pointer to a struct termios containing the new attributes.
44  * @return  Upon successful completion, returns 0; otherwise, returns -1 and sets errno to indicate the error.
45  *
46  * @note    This function sets the attributes of a terminal device specified by the file descriptor fd.
47  *          The act parameter determines when the attribute change takes effect:
48  *          - TCSANOW: Make the change immediately.
49  *          - TCSADRAIN: Make the change after all currently written data has been transmitted.
50  *          - TCSAFLUSH: Make the change after all currently written data has been transmitted, and discard
51  *            any received but unread data.
52  *          The new attributes are specified in the struct termios pointed to by tio.
53  *          The ioctl system call is used to set the attributes based on the value of act.
54  *          If the ioctl operation fails or an invalid action is specified, errno is set to indicate the error,
55  *          and the function returns -1.
56  */
tcsetattr(int fd,int act,const struct termios * tio)57 int tcsetattr(int fd, int act, const struct termios *tio)
58 {
59     switch (act)
60     {
61     case TCSANOW:
62         /* make the change immediately */
63         return (ioctl(fd, TCSETA, (void*)tio));
64     case TCSADRAIN:
65         /*
66          * Don't make the change until all currently written data
67          * has been transmitted.
68          */
69         return (ioctl(fd, TCSETAW, (void*)tio));
70     case TCSAFLUSH:
71         /* Don't make the change until all currently written data
72          * has been transmitted, at which point any received but
73          * unread data is also discarded.
74          */
75         return (ioctl(fd, TCSETAF, (void*)tio));
76     default:
77         errno = EINVAL;
78         return (-1);
79     }
80 }
81 
82 /**
83  * @brief   Gets the session ID of a terminal.
84  * @param   fd File descriptor of the terminal device.
85  * @return  Always returns 0.
86  *
87  * @note    This function is a stub and always returns 0.
88  *          In POSIX systems, tcgetsid() is used to get the session ID of the terminal associated with the file descriptor fd.
89  *          However, this function does not provide this functionality and simply returns 0 as a placeholder.
90  */
tcgetsid(int fd)91 pid_t tcgetsid(int fd)
92 {
93     return 0;
94 }
95 
96 /**
97  * @brief   Gets the output baud rate from a termios structure.
98  * @param   tio Pointer to a struct termios containing the terminal attributes.
99  * @return  Output baud rate extracted from the terminal attributes.
100  *
101  * @note    This function extracts the output baud rate from the termios structure pointed to by tio.
102  *          It retrieves the baud rate from the c_cflag member of the termios structure using the CBAUD mask.
103  *          The output baud rate is returned as a speed_t type.
104  */
cfgetospeed(const struct termios * tio)105 speed_t cfgetospeed(const struct termios *tio)
106 {
107     return tio->c_cflag & CBAUD;
108 }
109 
110 /**
111  * @brief   Gets the input baud rate from a termios structure.
112  * @param   tio Pointer to a struct termios containing the terminal attributes.
113  * @return  Input baud rate extracted from the terminal attributes.
114  *
115  * @note    This function is a wrapper for the cfgetospeed() function.
116  *          It returns the input baud rate by calling cfgetospeed() with the termios structure pointer tio.
117  */
cfgetispeed(const struct termios * tio)118 speed_t cfgetispeed(const struct termios *tio)
119 {
120     return cfgetospeed(tio);
121 }
122 
123 /**
124  * @brief   Sets the output baud rate in a termios structure.
125  * @param   tio Pointer to a struct termios where the output baud rate will be set.
126  * @param   speed Output baud rate to be set.
127  * @return  Upon successful completion, returns 0; otherwise, returns -1 and sets errno to indicate the error.
128  *
129  * @note    This function sets the output baud rate in the termios structure pointed to by tio.
130  *          The speed parameter specifies the baud rate to be set.
131  *          If the specified speed exceeds the CBAUD mask, indicating an invalid baud rate value,
132  *          errno is set to EINVAL, and the function returns -1.
133  *          Otherwise, the function clears the CBAUD bits in the c_cflag member of the termios structure
134  *          and sets them to the specified speed value. It then returns 0 to indicate success.
135  */
cfsetospeed(struct termios * tio,speed_t speed)136 int cfsetospeed(struct termios *tio, speed_t speed)
137 {
138     if (speed & ~CBAUD)
139     {
140         errno = EINVAL;
141         return -1;
142     }
143 
144     tio->c_cflag &= ~CBAUD;
145     tio->c_cflag |= speed;
146     return 0;
147 }
148 
149 /**
150  * @brief   Sets the input baud rate in a termios structure.
151  * @param   tio Pointer to a struct termios where the input baud rate will be set.
152  * @param   speed Input baud rate to be set.
153  * @return  Upon successful completion, returns 0; otherwise, returns -1 and sets errno to indicate the error.
154  *
155  * @note    This function sets the input baud rate in the termios structure pointed to by tio.
156  *          The speed parameter specifies the input baud rate to be set.
157  *          If the speed parameter is non-zero, indicating a valid baud rate, the function calls
158  *          cfsetospeed() to set both the input and output baud rates to the specified value.
159  *          If speed is zero, indicating that no baud rate needs to be set for input, the function returns 0
160  *          without making any changes to the termios structure.
161  */
cfsetispeed(struct termios * tio,speed_t speed)162 int cfsetispeed(struct termios *tio, speed_t speed)
163 {
164     return speed ? cfsetospeed(tio, speed) : 0;
165 }
166 
167 /**
168  * @brief   Sends a break signal on a terminal.
169  * @param   fd File descriptor of the terminal device.
170  * @param   dur Duration of the break signal (ignored).
171  * @return  Always returns 0.
172  *
173  * @note    This function is a stub and does not send an actual break signal.
174  *          Sending a break signal with a nonzero duration is implementation-defined,
175  *          so this function ignores the duration parameter and always returns 0.
176  */
tcsendbreak(int fd,int dur)177 int tcsendbreak(int fd, int dur)
178 {
179     /* nonzero duration is implementation-defined, so ignore it */
180     return 0;
181 }
182 
183 /**
184  * @brief   Flushes data from a terminal input or output queue.
185  * @param   fd File descriptor of the terminal device.
186  * @param   queue Queue to be flushed (TCIFLUSH, TCOFLUSH, or TCIOFLUSH).
187  * @return  Upon successful completion, returns 0; otherwise, returns -1 and sets errno to indicate the error.
188  *
189  * @note    This function flushes data from the input or output queue of the terminal device specified by the file descriptor fd.
190  *          The queue parameter specifies which queue to flush:
191  *          - TCIFLUSH: Flushes data from the input queue.
192  *          - TCOFLUSH: Flushes data from the output queue.
193  *          - TCIOFLUSH: Flushes data from both the input and output queues.
194  *          The ioctl system call is used with the TCFLSH command to perform the flush operation.
195  *          If the ioctl operation fails, errno is set to indicate the error, and the function returns -1.
196  */
tcflush(int fd,int queue)197 int tcflush(int fd, int queue)
198 {
199     return ioctl(fd, TCFLSH, (void*)(rt_ubase_t)queue);
200 }
201 
202 /**
203  * @brief   Controls the terminal flow control.
204  * @param   fd File descriptor of the terminal device.
205  * @param   action Action to be taken for flow control (TCOOFF, TCOON, TCIOFF, or TCION).
206  * @return  Upon successful completion, returns 0; otherwise, returns -1 and sets errno to indicate the error.
207  *
208  * @note    This function controls the flow of data on the terminal device specified by the file descriptor fd.
209  *          The action parameter determines the flow control action to be taken:
210  *          - TCOOFF: Suspends output transmission.
211  *          - TCOON: Restarts output transmission.
212  *          - TCIOFF: Suspends input transmission.
213  *          - TCION: Restarts input transmission.
214  *          The ioctl system call is used with the TCXONC command to perform the flow control operation.
215  *          If the ioctl operation fails, errno is set to indicate the error, and the function returns -1.
216  */
tcflow(int fd,int action)217 int tcflow(int fd, int action)
218 {
219     return ioctl(fd, TCXONC, (void*)(rt_ubase_t)action);
220 }
221 
222 /**
223  * @brief   Waits until all output written to the terminal is transmitted.
224  * @param   fd File descriptor of the terminal device.
225  * @return  Always returns 0.
226  *
227  * @note    This function is a stub and does not perform any action.
228  *          In POSIX systems, tcdrain() is used to wait until all output written to the terminal
229  *          is transmitted, but this function does not provide this functionality and simply returns 0 as a placeholder.
230  */
tcdrain(int fd)231 int tcdrain(int fd)
232 {
233     return 0;
234 }
235 
236 /**
237  * @brief   Sets the terminal attributes to raw mode.
238  * @param   t Pointer to a struct termios where the terminal attributes will be set.
239  *
240  * @note    This function sets the terminal attributes pointed to by t to raw mode.
241  *          Raw mode disables special input and output processing features, making the terminal behave more like a data stream.
242  *          The following modifications are made to the termios structure:
243  *          - Input flags (c_iflag) are cleared of various processing flags.
244  *          - Output flags (c_oflag) are cleared to disable output processing.
245  *          - Local flags (c_lflag) are cleared to disable canonical mode, echoing, and signal handling.
246  *          - Control flags (c_cflag) are modified to set character size to 8 bits and disable parity.
247  *          - The VMIN and VTIME control characters are set to 1 and 0, respectively, for non-blocking read behavior.
248  */
cfmakeraw(struct termios * t)249 void cfmakeraw(struct termios *t)
250 {
251     t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
252     t->c_oflag &= ~OPOST;
253     t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
254     t->c_cflag &= ~(CSIZE|PARENB);
255     t->c_cflag |= CS8;
256     t->c_cc[VMIN] = 1;
257     t->c_cc[VTIME] = 0;
258 }
259 
260 /**
261  * @brief   Sets the input and output baud rates in a termios structure.
262  * @param   tio Pointer to a struct termios where the input and output baud rates will be set.
263  * @param   speed Baud rate to be set for both input and output.
264  * @return  Upon successful completion, returns 0; otherwise, returns -1 and sets errno to indicate the error.
265  *
266  * @note    This function is a wrapper for the cfsetospeed() function.
267  *          It sets both the input and output baud rates in the termios structure pointed to by tio to the specified speed.
268  *          The function returns the result of cfsetospeed(), which sets the baud rate for both input and output.
269  */
cfsetspeed(struct termios * tio,speed_t speed)270 int cfsetspeed(struct termios *tio, speed_t speed)
271 {
272     return cfsetospeed(tio, speed);
273 }
274