3. Program Examples sample program
All Examples Have Been Derived from Miniterm.c. The Type Ahead Buffer Is Limited to 255 Characters, Just Like The Maximum String Length for Canonical Input Processing
oral
).
See the comments in the code for explanation of the use of the different input modes. I hope that the code is understandable. The example for canonical input is commented best, the other examples are commented only where they differ from the example for canonical input to Emphasize the differences.
The Descriptions Are Not Complete, But you are encouraged to experiment with the example. To derive the Best solution for your application.
Don't forget to give the appropriate serial ports the right permissions (e. G .: chmod a rw / dev / ttys1)!
All examples come from Miniterm.c. The Type Ahead buffer is limited to the size of 255 bytes, which is the same as the string of the CANONICAL INPUT process.
or
).
Note in the code explains the use of different input modes to hopes that these codes can be easily understood. The example of the standard input program has done the most detailed annotation, and other examples have been emphasized in a place different from the standard input example.
The narrative is not very complete, but you can motivate you to do experiments to this example to delay the best solution to the application you need.
Don't forget to give the serial port correct permissions (that is, CHMOD A RW / dev / TTYS1)!
3.1. Canonical Input Processing Standard Input Mode
#include
#include
#include
#include
#include
/ * baudrate settings area defined in
, which is includD by
* /
/ / Baud rate setting is defined
.
in
#define baudrate b38400
/ * Change this definition for the correct port * /// Define the serial number you need #define modemdevice "/ dev / ttys1" #define _posix_source 1 / * POSIX Compliant Source POSIX system compatible * / #define false 0 # define True 1 Volatile Int Stop = False; Main () {Int FD, C, Res; Struct Termios Oldtio, NewTIO; Char BUF [255]; / * Open modem device forreading and write and not assessing Tty Because We do't Want TO GET KILLED IF LINENOISE Sends Ctrl-c. Turn on the device is used to read and write, but do not control TTY mode, because we don't want to end this process after sending Ctrl-C * / fd = O_rdwr | o_nock ); If (fd <0) {PERROR (MODEMDEVICE); exit (-1);} Tcgetattr (FD, & Oldtio); // Save Current Serial Port Settings * // Store Current Serial Port Set Bzero (& NewTIO, SIZEOF) . newtio)); / * clear struct for new port settings * / // clear the new serial port settings structure / * BAUDRATE: set bps rate You could also use cfsetispeed and cfsetospeed CRTSCTS: output hardware flow control (only used if the. Cable Has All Ecessary Lines. See SECT. 7 of Serial-Howto) CS8: 8 N1 (8bit, No Parity, 1 Stopbit) Clocal: Local Connection, No Modem Contol Cread: Enable Receiving Characters Baudrate: Sets the transfer rate BPS of the serial port, you can also use cfsetispeed and cfsetospeed to set CRTSCTS: Output hardware flow control (only Under the cable of the full line, refer to the Serial-Howto Section 7) CS8: 8N1 (8-bit data, no parity bit, 1 bit stop bit) clocal: Local connection, no modem control CREAD: Allow received data * / newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; / * IGNPAR: ignore bytes with parity errors ICRNL: map CR to NL (otherwise a CR input on the other computer will not terminate input) otherwise make device Raw (No Other Input Processing) ignpar: Ignually ICRNL ignoring the parity error: Put the CR image into NL (otherwise the CR from other machines cannot terminate) or set the device to the RAW state (
Without additional input processing) * / newTIO.C_IFLAG = IGnPar | ICRNL; / * RAW OUTPUT. RAW mode output * / newTIO.C_OFLAG = 0; / * ICANON: ENABLE CANONICAL INPUT Disable All Echo functionality, and don't send signals To call Program Icanon: Start the standard output, close all Echo features, no signal signal * / newTIO.C_LFLAG = ICANON; / * Initialize All Control Characters Default Values Can Be Found In /usr/include/termios.h, And are given in the comments, but we don't need new Therm Here Initialize all control characters, the default value can be found in /usr/include/termios.h, and have an annotation, but we don't need to consider these * / NEWTIO.C_CC [VINTR] = 0; / * Ctrl-c * / newtio.c_cc [vquit] = 0; / * ctrl- / * / newTIO.C_CC [VERASE] = 0; / * DEL * / NEWTIO.C_CC [ Vkill] = 0; / * @ * / newtio.c_cc [veof] = 4; / * ctrl-d * / newTIO.c_cc [vTIME] = 0; / * inter-character time unused * / / * does not use characters Timer * / newTIO.C_CC [VMIN] = 1; / * blocking read untric 1 character arrives * / / * block until reading a character * / newTIO.C_CC [vSWTC] = 0; / * '/ 0 '* / NEWTIO.C_CC [vStart] = 0; / * Ctrl-q * / newTIO.C_CC [vStop] = 0; / * Ctrl-s * / newtio.c_cc [vsusp] = 0; / * Ctrl-z * / newtio. C_cc [veol] = 0; / * '/ 0' * / newTIO.C_CC [Vreprint] = 0; / * Ctrl-r * / newTIO.C_CC [vdiscard] = 0; / * Ctrl-u * / newTIO.C_CC [Vwerase] = 0; / * Ctrl-w * / newTIO.C_CC [VLNext] = 0; / * Ctrl-v * / newTIO.C_CC [veol2] = 0; / * '/ 0' * / / / * now clean The MODEM LINE and ACTIVATE The Settings for the Port Clears the data cable, start the new serial settings * / TCFLUSH (FD, TCIFLUSH); TCSetattr (FD, Tcsanow, & NewTIO);
/ * Terminal Settings Done, NOW Handle Input In this Example, Inputting A 'Z' At the beginning of a line will exit the program. Terminal settings, now you can handle data in this program, start entering one in a row 'Z' Termination of the program * / while (stop == false) {/ * loop unsteil we have a Terminating condition * / / / loop until the termination condition / * Read blocks Program Execution Until a line Terminating Character Is Input, Even if more than 255 chars are input. If the number of characters read is smaller than the number of chars available, subsequent reads will return the remaining chars. res will be set to the actual number of characters actually read even if the input exceeds 255 bytes The segment read segment will still be stopped at the end of the line. If the read characters are less than the number of characters that should be obtained, the remaining character is read at the next reading. RES is used to get the number of bytes that you really read each time * / res = read (FD, BUF, 255); buf [res] = 0; / * set end of string, so we can printf * / // set characters The string end of the string, so that Printf Printf (":% s:% D / N", BUF, RES) can be successfully used; if (buf [0] == 'z') stop = true;} / * rest port port Settings Restore Old Serial Sets * / TcSetattr (FD, Tcsanow, & Oldtio);} 3.2. Non-Canonical Input Processing Non-standard Input Mode
In non-canonical input processing mode, input is not assembled into lines and input processing (erase, kill, delete, etc.) does not occur Two parameters control the behavior of this mode:. C_cc [VTIME] sets the character timer, and C_CC [vmin] sets the minimum number of character of character of character satisfying the read.
IF min> 0 and time = 0, min sets the number of character = 0, the time the read is satisfied. As time is zero, The Timer is not used.
IF min = 0 and time> 0, Time Serves as a timeout value. The read will be satisfied if a single character is read, or time is exceeded (time * 0.1 s). If Time is Exceeded, No Character Will BE returned.If MIN> 0 and TIME> 0, TIME serves as an inter-character timer. The read will be satisfied if MIN characters are received, or the time between two characters exceeds TIME. The timer is restarted every time a character is received And Only Becomes Active After The First Character Has Been Received.
If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of characters currently available, or the number of characters requested will be returned. According to Antonino (see contributions), you could issue a fcntl (fd, F_SETFL, BEDELAY); Before Reading to Get The Same Result.
By modifying newtio.c_cc [vTIME] and newtio.c_cc [vmin] all model described Above can be tsted.
In non-standard input mode, the input data is not combined, nor does ERASE, KILL, and DELETE and other input processing. We just use two parameters to control the input behavior of this mode: c_cc [vTIME] set the timer in the character input interval, and the c_cc [vmin] sets the minimum byte number of the read function.
MIN> 0, Time = 0: The read function returns after reading the number of characters that read the MIN value.
MIN = 0, TIME> 0: Time determines the timeout value, the read function is reading a character, or waiting for the reading time to returns after the Time (T = Time * 0.1s), that is, even The data is read in the serial port, and the read function will return after the Time time.
MIN> 0, Time> 0: After receiving the data of the Min byte, the read function is returned after the data is received. This timer will retrieve when the character is received, and will only start after receiving the first byte.
MIN = 0, Time = 0: The read function will return immediately. The number of characters actually read, or the number of characters to be read will be returned as the return value. According to Antonino, FCNTL (FD, F_SETFL, FNDELAY) can be used to obtain the same result before reading.
Change Nettio.c_cc [vtime] and newTIO.C_CC [VMIN] can test the above settings.
#include
#include
#include
#include
#include
#define baudrate b38400 # Define modemDevice "/ dev / ttys1"
#define _posix_source 1 / * POSIX Compliant Source * / #define false 0 #define true 1 Volatile Int Stop = false; main () {Int FD, C, Res; Struct Termios Oldtio, NewTIO; Char BUF [255]; fd = Open (ModeMDevice, O_RDWR | f (fd <0) {PERROR (MODEMDEVICE); EXIT (-1);} Tcgetattr (fd, & oldtio); / * Save Current Port Settings * / Bzero (& NewTIO, SIZEOF (NewTIO )); NewTIO.C_CFLAG = Baudrate | CRTSCTS | CS8 | CLOCAL | CREAD; NewTIO.C_IFLAG = IGnPAR; NewTIO.C_OFLAG = 0; / * SET INPUT MODE (Non-Canonical, No echo, ...) * / /////////// Setting the input mode to non-standard input newTIO.C_LFLAG = 0; newTIO.C_CC [vTIME] = 0; / * inter-character timer unused * / / not use character interval timer newTIO.C_CC [vmin] = 5; / * BLOCKING READ UNTIL 5 Chars Received * / / After receiving 5 characters, the read function returns TCFlush (FD, TCIFLUSH); TCSetattr (FD, Tcsanow, & NewTIO); while (stop == false) {/ * loop for INPUT * / RES = Read (FD, BUF, 255); / * RETURns After 5 Chars Have Been Input * / BUF [RES] = 0; / * SO We can Printf ... * / printf (":% s:% d / n ", buf, res); if (BUF [0] == 'Z') stop = true;} TcSetattr (FD, Tcsanow, & Oldtio);
3.3. Asynchronous INPUT asynchronous input mode
#include
#include
#include
#include
#include
#include
#define baudrate b38400
#define modemdevice "/ dev / ttys1"
#define _POSIX_SOURCE 1 / * POSIX compliant source * / #define FALSE 0 #define TRUE 1 volatile int STOP = FALSE; void signal_handler_IO (int status); / * definition of signal handler * / // definition of signal handler int wait_flag = TRUE / * True While No Signal Received * // True represents no signal, waiting for main () {Int fd, c, res; struct termios oldtio, newTIO; struct sigaction saio; / * definition of signal action * / // Define the structure of the signal processing Char BUF [255]; / * Open the device to be non-blocking (read will return immediatly) * / / / is the use of non-blocking mode to open the device read function immediately returned, will not block FD = Open (ModemDevice, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd <0) {PERROR (MODEMDEVICE); EXIT (-1);} / * Install the meansal handler before make Making the device asynchronous * // In progress device asynchronous transmission Before, the installation signal handler saio.sa_handler = signal_handler_io; saio.sa_mask = 0; saio.sa_flags = 0; saio.sa_ RESTORER = NULL; SIGACTION (SIGIO, & SAIO, NULL); / * ALLOW The process to receive sigio * // Allow the process to receive SIGIO signal FCNTL (FD, F_SETOWN, getPID ()); / * make the file descriptor asynchronous (the Manual Page Says Only o_append and o_nonblock, will work with f_setfl ... * / / / / / / / / / / 设置 设置 m m m 上; 上;;;;;;;;;;;;;;;;;;; (FD, & OLDTIO); / * SAVE CURRENT Port Settings * / / / * SET New Port Settings for Canonical Input Processing * / / / Set new serial port for standard input mode NewTIO.C_CFLAG = Baudrate | CRTSCTS | CS8 | CLOCAL | CREAD; NEWTIO.C_IFLAG = IGNPAR | ICRNL; NewTIO.C_OFLAG = 0;
NEWTIO.C_LFLAG = ICANON; newTIO.C_CC [VMIN] = 1; newTIO.C_CC [VTIME] = 0; TCFLUSH (FD, TCIFLUSH); TcSetattr (fd, tcsanow, & newtio); / * loop while waiting for infut. Normally WE Would Do Something Useful Here Loop Waiting for Enter, usually we will do something here * / while (stop == false) {printf ("./ n"); usleep (100000); / *After receiving sigio, Wait_Flag = False, input * / / After receiving the SIGIO signal, wait_flag = false, indicates that IF (Wait_Flag == false) {RES = Read (FD, BUF, 255) ); Buf [res] = 0; Printf (":% s:% d / n", buf, res); if (res == 1) stop = true; / * stop loop if only a cr at * / Wait_flag = true; / * Wait for new INPUT Waiting for new input * /} / * restore old port set settings * / tcsetttr (fd, tcsanow, & oldtio);} / ************ *********************************************************** ************ * Signal Handler. Sets Wait_Flag To False, To Indicate Above Loop That * * CHARACTERS HAVE BEEN RECE Ived. * **************************************************************** ***************************** / / / signal processing function, setting WAIT_FLAG to False to tell the above loop function serial port to receive characters Void signal_handler_io (int statin) {Printf ("Received Sigio Signal./N"); Wait_Flag = false;} 3.4. Waiting for Input from Multiple Sources Waiting for input from multiple sources
This Section is Kept TO A Minimum. It is just intended to beh hint, and thereforefore the Example Code is Kept Short. This Will Not Only Work With Serial Ports, But with any set of file descriptors.
The select call and accompanying macros use a fd_set. This is a bit array, which has a bit entry for every valid file descriptor number. Select will accept a fd_set with the bits set for the relevant file descriptors and returns a fd_set, in which the Bits for the File Descriptor, or an exception Occurred. All Handling of fd_set is done with the provided macros. See Also The Manual Page SELECT (2) This part is very small, just as a prompt, So this code is also very short. And this part of the content is not only for serial port programming, but also for any set of file descriptors.
SELECT calls and their corresponding macros, using fd_set. This is a bit array, where each bit represents a valid file description symbol. SELECT calls receive a valid file descriptor structure and returns an FD_SET bit array. If a bit is set to 1 in this bit array, an input, output or exception occurred in the corresponding file descriptor. All fg_set's processing is provided by macros, and the specific reference is Man SELECT 2.
#include
#include
#include
Main ()
{
INT FD1, FD2; / * Input Sources 1 and 2 Input Source 1 and 2 * /
FD_SET READFS; / * File Descriptor set * /
INT MAXFD; / * Maximum File Desciptor Used the maximum value of the file descriptor * /
INT loop = 1; / * loop while true cycle logo * /
/ * Open_INPUT_SOURCE OPENS A Device, Sets The Port Correctly, And
Returns A File Descriptor * /
// Open_INPUT_SOURCE function Open a device, set the port correctly, and return to the file descriptor
FD1 = OPEN_INPUT_SOURCE ("/ dev / ttys1"); / * COM2 * /
IF (fd1 <0) exit (0);
FD2 = OPEN_INPUT_SOURCE ("/ dev / ttys2"); / * COM3 * /
IF (fd2 <0) exit (0);
Maxfd = max (FD1, FD2) 1; / * Maximum Bit Entry (fd) to Test * /
/ * loop for input * /
While (loop) {
FD_SET (FD1, & ReadFS); / * SET TESTING Forum 1 * /
FD_SET (FD2, & Readfs); / * set testing for source 2 * /
/ * block unient INPUT BECOMES AVAILABLE blocks until you have entered * /
SELECT (MAXFD, & ReadFS, NULL, NULL, NULL);
IF (fd_isset (fd1)) / * Input from Source 1 Available Source 1 has input * / handle_input_from_source1 ();
IF (fd_isset (fd2)) / * Input from Source 2 Available Source 2 has input * /
Handle_INPUT_FROM_SOURCE2 ();
}
} The Given Example Blocks Indefinitely, UnTil Input from One of the Sources Becomes Available. If you need to timeout on Input, Just Replace the select call by: This example can cause unknown blocking, knowing one of the sources have data input. If you need to set a timeout value for the input, use the following SELECT:
Int res;
Struct TimeVal Timeout;
/ * Set Timeout Value With Input Loop Sets the timeout value in the input loop * /
Timeout.tv_usec = 0; / * MilliseConds Sets milliseconds * /
Timeout.tv_sec = 1; / * Seconds Settings the number of seconds * /
Res = SELECT (MAXFD, & Readfs, Null, Null, & Timeout);
IF (res == 0)
/ * Number of file descriptors with input = 0, timeout accurred. All file descriptors are not entered, timeout exits returns 0 * /
This example will timeout after 1 second. If a timeout occurs, select will return 0, but beware that Timeout is decremented by the time actually waited for input by select. If the timeout value is zero, select will return immediatly. This example will After 1 second, I will exit. If timeout occurs, select returns 0, please note that timeout is decremented by the time according to the actual waiting input, if Timeout is set to 0, the SELECT function will immediately exit.
Other Sources of Information Other Resource Information
· The Linux Serial-HOWTO Describes How To Set Up Serial Ports and Contains Hardware Information.
Linux Serial Howto introduces how to install serial ports and include hardware information.
· Serial Programming Guide for POSIX Compliant Operating Systems, by Michael Sweet.
Serial programming on the POSIX compatible operating system
· The Manual Page Termios (3) Describes All Flags for the Termios Structure.
Man Termios 3 describes settings in all Termios structures.