|
由于实验需要编写了一个串口操作程序(当然是写得满头大汗),操作系统环境是
redhat 9.0,编译器是自带的gcc-3.2.2-5。下面是代码清单,贴出来共享:
file1: serial_port.h
[code:1]
#ifndef __SERIAL_PORT_H__
#define __SERIAL_PORT_H__
#include <termios.h> // POSIX terminal control definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
class serial_port
{
public:
serial_port() {fd = -1;}
virtual ~serial_port() {};
bool open_port();
bool close_port();
bool write_to(char *pin, int buffer_length);
bool read_from(char *pout, int &buffer_length);
inline bool query(); // return true if already open
int getfile() {return fd;}
char port[80]; // serial port name
long BAUD; // baud rate
long DATA; // data bits
long STOP; // stop bits
long PARITYON;
long PARITY;
private:
int fd; // file descriptor for the port
// place for old and new port setting for serial port
struct termios oldtio, newtio;
};
#endif
[/code:1]
file2: serial_port.cpp
[code:1]
#include <assert.h>
using namespace std;
#include "serial_port.h"
bool serial_port::open_port()
{
assert(query() == false);
// open the serial port to be non-blocking (read will return immediately
)
fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {
fd = -1;
return false;
}
assert(query() == true);
tcgetattr(fd, &oldtio); // save current port setting
// set new port settings for canonical input processing
newtio.c_cflag = BAUD | CRTSCTS | DATA | STOP | PARITYON | PARITY | CLOC
AL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
newtio.c_lflag = 0; // ICANON
newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
return true;
}
bool serial_port::close_port()
{
assert(query() == true);
// restore old port setting
tcsetattr(fd, TCSANOW, &oldtio);
close(fd);
fd = -1;
assert(query() == false);
}
bool serial_port::write_to(char *pin, int buffer_length)
{
assert(query() == true);
int write_length = write(fd, pin, buffer_length);
if (write_length != buffer_length) return false;
return true;
}
bool serial_port::read_from(char *pout, int &buffer_length)
{
assert(query() == true);
buffer_length = read(fd, pout, buffer_length);
if (buffer_length < 0) return false;
return true;
}
bool serial_port::query()
{
return fd > 0;
}
[/code:1]
file3: main.cpp
[code:1]
#include <iostream>
#include <string>
#include <sys/signal.h>
using namespace std;
#include "serial_port.h"
char device[80]; // name of device to open
const char device_def[] = "/dev/ttyS0"; // default device if none specified on c
ommand line
int t_option = 0; // set if -t option is used
int r_option = 0; // set if -r option is used
const int SIZE = 101;
// print command usage and exit
void usage()
{
cerr << "usage:serialhandler [-t | -r] [device]\n";
cerr << " -t option sends bits via device specified\n";
cerr << " -r option receives bits from device specified\n";
cerr << " default device is " << device_def << endl;
exit(1);
}
// handle command line options
void parse_args(int argc, char *argv[])
{
const char *flags = "tr";
int c;
while ((c = getopt(argc, argv, flags)) != EOF) {
switch (c) {
case 't':
t_option = 1;
break;
case 'r':
r_option = 1;
break;
case '?':
usage();
break;
}
}
if (t_option + r_option > 1) {
cerr << "serialhandle: options are mutually exclusive\n";
usage();
}
// check for a single additional argument
if ((argc - optind) > 1)
usage(); // too many arguments
if ((argc - optind) == 1)
strcpy(device, argv[optind]); // one argument
}
bool wait_flag = false; // false while no signal received
void signal_handler_IO(int status) // definition of signal handler
{
// cout << "received SIGIO signal\n";
wait_flag = true;
}
void install_handler(int fd)
{
struct sigaction saio; // definition of signal action
// install the serial handler before making the device asynchronous
saio.sa_handler = signal_handler_IO;
sigemptyset(&saio.sa_mask); // saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO, &saio, NULL);
// allow the process to receive SIGIO
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...)
fcntl(fd, F_SETFL, FASYNC);
}
int main(int argc, char *argv[])
{
// parse command line arguments
strcpy(device, device_def);
parse_args(argc, argv);
serial_port *port = new serial_port;
strcpy(port->port, device);
port->BAUD = B4800;
port->DATA = CS8;
port->STOP = 0;
port->PARITYON = 0;
port->PARITY = 0;
if (port->open_port() != true) {
cerr << "unable to open device - " << device << endl;
delete port;
exit(1);
} else {
assert(port->query() == true);
cout << "device - " << device << " successfully opened\n";
}
int fd = port->getfile(); // get the file descriptor
install_handler(fd); // install the serial handler
char *buffer = new char[SIZE];
if (r_option == 0) {
while (/*cin.get() != EOF*/ 1) {
cin.getline(buffer, SIZE/*, '\n'*/);
buffer[strlen(buffer)] = '\n';
if (!port->write_to(buffer, strlen(buffer)))
cerr << "write failure" << endl;
memset(buffer, 0, SIZE);
sleep(1);
}
} else {
int buffer_length;
while (/*cin.get() != EOF*/ 1) {
if (wait_flag == true) {
// cout << "received SIGIO signal\n";
buffer_length = SIZE;
if (!port->read_from(buffer, buffer_length))
cerr << "read failure" << endl;
if (buffer_length > 0)
cout << buffer/* << endl*/;
memset(buffer, 0, SIZE);
wait_flag = false;
}
sleep(1);
}
}
delete [] buffer;
assert(port->query() == true);
port->close_port();
assert(port->query() == false);
delete port;
}
[/code:1]
干脆连Makefile也贴上吧,呵呵:
[code:1]
INCL =
CFLAGS = -O2 -g
LFLAGS =
LIBS =
CC = g++
serialhandler: main.o serial_port.o
$(CC) $(LFLAGS) -o serialhandler main.o serial_port.o
main.o: main.cpp serial_port.h
serial_port.o: serial_port.cpp serial_port.h
clean:
rm -f serialhandler
rm -f main.o
rm -f serial_port.o
.SUFFIXES: .cpp
.cpp.o:
$(CC) -c $(CFLAGS) $(INCL) -o $@ $<
[/code:1]
总算完了,下面我有几个问题想请教
这个程序现在还有一个小小的bug
如果在终端以-t方式运行程序,在命令行中输入字串回车,则发送出该字串,
可是当字串长度等于或超过32时,就会在发出该字串后自动发送回车符,其原因
是getline那一句不起作用了,直接跳过去了,就开始不停的循环
为什么会这样,我怀疑和以下问题相似:
http://mathbits.com/MathBits/CompSci/APstrings/APgetline.htm
可是用同样的方法根本无法修正此bug,况且我在getline之前并没有
调用cin >>呀
还有一个问题我已经避过去了,但是问题的原因还没有想明白
起初的程序输出用的是cout << buffer << endl
这个时候如果向该串口发送字符超过8个,将会以8为单位进行截断
也就是说,我发送的是:
aaaaaaaaaaaaaaaaaaaa
但接收的却是:
aaaaaaaa
aaaaaaaa
aaaa
用gdb调试时却一切正常(难道延时能解决问题?)
这究竟是怎么回事?
我是个新手,还没入门,请多多指点
万分感激!!!!!!! |
|