2.3. Input Concepts for Serial Devices Enterging Concepts of Serial Pit Equipment Here Three Different Input Concepts Will Be Presented. The appropriate Concept
Has to be chosen for the intended Application. WHENEVER POSSIBLE, DO NOT loop Reading
Single Characters to Get a Complete String. When I Did this, I Lost Characters,
WHEREAS A Read for The Whole string Did Not show any.
Here will introduce three different input methods of serial devices, you need to choose the right way for your program. Any
In the case of possible, do not use loop read single characters to get a string. When I did this, I just
Lost characters, and read the Read method of the entire string, there is no such error.
2.3.1. Canonical Input Processing Standard Input Mode This Is The Normal Processing Mode for Terminals, But Can Also BE Useful for Communicating
WITHER DL INPUT IS Processed in Units of Lines, Which Means That A Read Will
ONLY RETURN A FULL LINE OF INPUT. A line is by default terminated by a nl (ASCII
LF), an end of file, or an end of line character. A Cr (The Dos / Windows Default
End-of-line) Will NOT TERMINATE A LINE with the default settings.
Canonical Input Processing Can Also Handle The Erase, Delete Word, And Reprint
Characters, Translate Cr To NL, ETC ..
This is the standard processing mode of the terminal device, which is also useful in the input communication with other DLs. This party
In the formula, the READ will return to a full line of complete input. The end of the one-line, the default is NL (ASCII value LF), file knot
Brass, or a row end character. In the default setting, Cr (the default line end in DOS / Windows is not
Row end sign.
Standard input processing can also handle clear, delete words, redraw characters, conversion CRs NL, and the like.
2.3.2. Non-Canonical Input Processing Non-standard Input Patterns Non-Canonical Input Processing Will Handle A Fixed Amount of Characters Per Read,
And Allows for a Character Timer. This Mode SHOULD BE Used if your application
Always Read a fixed number of character of character of characters, or if the connection device sends burs
Of character.
Non-standard input processing can be used to read the fixed quantity character each time and allow the use of characters to receive time
Timer. This mode can be used in a program that reads a fixed length string, or the connected device will suddenly send
In the case of a large number of characters.
2.3.3. Asynchronous Input asynchronous input mode The Two modes described Above Can Be buy in synchronous and askRONM MODE.SYNCHRONONKED, WHERE A Read Statement Will Block, UnTil The Read IS
Satisfied. in Asynchronous Mode The Read Statement Will Return Immediatly and Send
A Signal To The Calling Program Upon Completion. This Signal Can Be Received By
A Signal Handler.
The two modes described above can be used in synchronous and asynchronous transmission modes. The default is working in synchronous mode, too
The status of the READ will be blocked (Block) before the data is not read. And in asynchronous mode, the state of the READ
A signal to the called program will be returned immediately and send a signal to the call until work. This signal can be received by the signal processing program handler.
2.3.4. Waiting for Input from Multiple Sources Waiting for Input from Multi-Source This Is Not A Different Input Mode, But Might Be Useful, IF you are handling multiple
Devices. in My Application I WAS Handling Input over A TCP / IP Socket and Input over
A Serial Connection from another computer quasi-simultaneously. The Program EXAMPLE
Given Below Will Wait for Input from Two Different Input Sources. If INPUT from ONE
Source Becomes Available, IT Will Be Processed, And The Program Will Then Wait for
NEW INPUT.
The Approach Presented Below Seem Rather Complex, But it is important to keep in
Mind That Linux Is a Multi-Processing Operating System. The SELECT SYSTEM CALL WILL
NOT LOAD THE CPU While Waiting for Input, Whereas Looping Until Input Becomes
Available Would Slow Down Other Processes Executing At The Same Time.
This section is not another input mode, but if you want to handle data from multiple devices, it may be very
use. In my application, I need to handle other calculations at the same time through a TCP / IP socket and a serial port.
Enter from the machine. The sample program given below will wait for input from two different input sources. If one of the signals
The source appears, the program will be handled accordingly, and the program will continue to wait for new inputs.
The method raised later seems quite mix, but remember that Linux is a multi-process operating system. System call
SELECT does not increase the burden of the CPU when waiting for the input signal, and if the polling method is used to wait for the input signal
If you will slow down other processes that are being executed.
3. Program Examples Sample Program All Examples Have Been Derived from Miniterm.c. The Type Ahead Buffer IS Limitedto 255 Characters, Just Like The Maximum String Length for Canonical Input Processing
(
SEE the Comments in the code for expent ion of the use of the defvent input.
I hope what the code is understandable. The Example for Canonical Input is comments
BEST, THE OTHER EXAMPLES Are Comment Only Where The Difer from The Example for
CANONICAL INPUT TO EMPHASIZE The DIFFERENCES.
The Descriptions Are Not Complete, But You Are Encouraged To Experiment with The
Examples 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, this with the standard
The string of the Canonical Input process is the maximum length of the same length (
Note in the code explains the use of different input modes to hopes that these codes can be easily understood. Standard input program
Examples have made the most detailed annotations, and other examples have been emphasized in places that differ from standard input examples.
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
Code
#include
#include
#include
#include
#include
/ * baudrate settings area defined in
// 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 as controlling
Tty Because We don't want to get killed if linenoise senends ctrl-c.
Turn on the device for reading and writing, but do not control TTY mode, because we don't want to send Ctrl-C
After the end of this process
* /
FD = Open (ModemDevice, o_rdwr | o_nock ";
IF (fd <0) {PERROR (MODEMDEVICE); EXIT (-1);
Tcgetattr (fd, & oldtio); / * Save Current Serial Port Settings * /
// Store the current serial settings
Bzero (& NewTIO, SIZEOF (NewTIO)); / * Clear Struct for New Port Settings * /
/ / Empty new serial port set 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: 8N1 (8bit, No Parity, 1 STOPbit)
Clocal: Local Connection, No Modem Contol
CREAD: Enable Receiving Characters
BaudRate: Set the transfer rate BPS of the serial port, you can also use cfsetispeed and cfsetospeed to set
CRTSCTS: Output hardware flow control (only work under the cable with complete lines, refer to Serial-Howto Section 7)
CS8: 8N1 (8-bit data for each frame, no parity check, 1 bit stop bit)
CLOCAL: Local connection, no modem control
CREAD: Allows receiving 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 NOT
Terminate Input) OtherWise Make Device Raw (No Other Input Processing)
Ignpar: Ignore parity error
ICRNL: Take the CR image into NL (otherwise the CR from other machines cannot terminate) or set the device
For the RAW status (no 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 calling program
ICANON: Start the standard output, close all ECHO functions, send signals to the program
* /
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 Them Here
Initialize all control characters, the default value can be found in /usr/include/termios.h,
And have an annotation, but here 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 Timer Unused * /
/ * Do not use timers in characters * /
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
Clear the data cable, start a new serial setting
* /
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.
The terminal setting is complete, and the data can now be handled.
In this program, enter a 'Z' in a row, will terminate the program.
* /
While (stop == false) {/ * loop untric we have a Terminating condition * /
/ / Circulation until the termination conditions are met
/ * Read Blocks Program Execution Until a line Terminating Character IS
Input, Even IF More Than 255 Chars Are Input. if The Numberof 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 you enter more than 255 bytes, the segment read segment will still be stopped until the end of the end.
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 really read each time
* /
Res = Read (FD, BUF, 255);
BUF [RES] = 0; / * SET End of String, So We can Printf * /
// Set the string end of the string, so that printf can be used smoothly
Printf (":% S:% D / N", BUF, RES);
IF (Buf [0] == 'Z') stop = true;
}
/ * Restore the old port set settings Restore old serial settings * /
TcSetattr (fd, tcsanow, & oldtio);
}
3.2. Non-Canonical Input Processing Non-standard Input Patterns in non-canonical Input Processing Mode, Input Is Not Assembled INTO LINES AND INPUT
Excessing (Erase, Kill, Delete, etc.) Does Not Occur. Two Parameters Control There
Behavior of this mode: c_cc [vTIME] sets the character timer, and c_cc [vmin] sets
The minimum number of character of character satisfying the read.
IF
MIN> 0 and time = 0, min sets the number of character of character of characters to receive before
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 (t = 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 character receifled, 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 ofcharacters currently available, or the number of characters Requested Will Be Returned.
According to Antonino (See Contributions), You Could Issue A FCNTL (FD, F_SETFL, FNDELAY);
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, and ERASE, KILL, DELETE, etc.
Incorporation. We just use two parameters to control the input behavior of this mode: c_cc [vTIME] sets the character input
The timer of the separation time, and the c_cc [vmin] sets the minimum number of bytes that satisfy 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 reading
Take the time over Time (t = time * 0.1s) back, that is, even if you don't read the number from the serial port
According to the reading function, it will return after the Time time.
Min> 0, Time> 0: After reading the data of the Min byte, the read function is confiscated by the TIME time
Returns it to the data. This timer will retrieve the first byte while receiving the first byte while receiving the first byte while receiving the first byte.
start up.
MIN = 0, Time = 0: The read function will return immediately. The number of characters that actually read, or the characters to be read
The number will be returned as the return value. According to Antonino, FCNTL (FD, F_SETFL,
Fndelay, get the same result before reading.
Change Nettio.c_cc [vtime] and newTIO.C_CC [VMIN] can test the above settings.
Code
#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 | o_nock ";
IF (fd <0) {PERROR (MODEMDEVICE); EXIT (-1);
Tcgetattr (FD, & Oldtio); / * Save Current Port Settings * /
Bzero (& 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 is non-standard input
NEWTIO.C_LFLAG = 0;
NEWTIO.C_CC [VTIME] = 0; / * Inter-character Timer Unused * /
/ / Not using a character interval timer
NEWTIO.C_CC [VMIN] = 5; / * blocking read unientil 5 chars received * /
// After receiving the number of 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
Code
#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 stat); / * definition of signal handler * /
/ / Define the 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) * /
// Yes to open the device read function immediately with a non-blocking mode, it will not block
FD = Open (ModemDevice, O_RDWR | O_NOCTTY | O_NONBLOCK);
IF (fd <0) {PERROR (MODEMDEVICE); EXIT (-1);} / * Install the device isynchronous * /
/ / Install the signal handler before performing an apparatus asynchronous transmission
Saio.sa_handler = signal_handler_io;
SAIO.SA_MASK = 0;
SAIO.SA_FLAGS = 0;
Saio.sa_restorer = NULL;
Sigction (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 ... * /
/ / Set the file descriptor of the serial port as an asynchronous, and the Man said, only o_append and o_nonblock can use f_setfl
FCNTL (FD, F_SETFL, FASYNC);
Tcgetattr (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 10 Do Something
Useful Here loops Wait for input, usually we will do other things here * /
While (stop == false) {
Printf ("./ n"); USLEP (100000);
/ * after receiving sigio, wait_flag = false, input is availableand can be ready * /
// After receiving the SIGIO signal, wait_flag = false, indicating that there is input, and can read it.
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 Wait a new input * /
}
}
/ * Restore Old Port Settings * /
TcSetattr (fd, tcsanow, & oldtio);
}
/ ************************************************** ************************** SIGNAL HANDLER. SETS WAIT_FLAG to FALSE, TO INDICATE ABOVE LOOP THAT *
* CHARACTERS HAVE BEEN Received. *
*********************************************************** ************************ /
// Signal processing function, set wait_flag to false to tell the above loop function serial port to receive characters
void signal_handler_io (int status) {
Printf ("Received Sigio Signal./N");
WAIT_FLAG = FALSE;
}
3.4. Waiting for Input from Multiple Sources Waiting for the input of multiple sources This section section Kept to be a minimum. It is just intended to be a 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 Descriptors Are Set Where Input, Output, or An Exception
Occurred. All Handling of Fd_set is Done with the provided macros. See Also The PROX
Manual Page SELECT (2).
This part is very little content, just as a prompt, so this code is also very short. And this part of the content is not only suitable
For serial port programming, and suitable for any set of file descriptors.
SELECT calls and their corresponding macros, using fd_set. This is a bit array, where each bit represents one
Effective file description symbol. SELECT calls to receive a valid file descriptor structure and return FD_SET bit
Array, if a bit is set to 1 in this bit array, it means that the corresponding file descriptor has an input, output or
There are exceptions. All fg_set's processing is provided by macros, and the specific reference is Man SELECT 2.
Code
#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 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 of data input. If you need to set a timeout value for the input, use the following SELECT:
Code
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.