Linuxシリアルポートプログラミングは一度にすべての入力データを読み取る(入力データが不定長)


プログラミングの背景:ボードはlinux 2.6.39システムで、ヒューマンマシンインタラクティブインターフェースはボード上のシリアルポートです.コマンドを入力すると、長さが8より大きい場合、readが読み取ったデータは複数回に分けて得られる(シリアルポートは非ブロックモードでデータを読み取る)、例えば入力した文字の長さが25(ループ読み出し、以下コードを貼る):初めて8個を読み取り、シリアルポート割り込み(割り込みが発生すると途中でデータが読めなくなり、実測)が発生し、その後8個、8個、1つ('0'は占めていません)、原因を調べてみると、多くのネットユーザーもこの問題に直面して、いくつかの投稿を見ても直接解決方法を言わなかった.これはシリアルポート装置のバッファリングと関係があり、一般的なバッファサイズは8 bytesで、データが受信できる以上、自分でコードを引っ張って一度に受信し、所定の受信が満たされるまでキャッシュに入れます.
プログラミング目的:シリアルポートは任意の長さの文字列(上限あり)を入力し、キャッシュ文字配列に入れる
#include <stdio.h>
#include <stdlib.h> 
#include <unistd.h>  
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> 
#include <termios.h>
#include <errno.h>  
#include <string.h> 
#include <limits.h> 
#include <asm/ioctls.h>
#include <time.h>
#include <pthread.h>
#include "GPRS.h"

#define DATA_LEN                0xFF
#define BUFSIZE                 512  


char read_buf[256] = {'\0'};
char read_nBytes[10] = {0};
 
int openSerial_GPRS(char *cSerialName, unsigned int Baud)
{
    int iFd;
    struct termios opt; 
	
    iFd = open(cSerialName, O_RDWR|O_NOCTTY|O_NONBLOCK|O_NDELAY);//|O_NONBLOCK                
	
    if(iFd < 0) {
        perror(cSerialName);
        return -1;
    }
	
    tcgetattr(iFd, &opt);      

	switch(Baud)
	{
		case 115200: cfsetispeed(&opt, B115200);cfsetospeed(&opt, B115200);break;
		case  57600: cfsetispeed(&opt, B57600);cfsetospeed(&opt, B57600);break;
		case  38400: cfsetispeed(&opt, B38400);cfsetospeed(&opt, B38400);break;
		case  19200: cfsetispeed(&opt, B19200);cfsetospeed(&opt, B19200);break;
		case   9600: cfsetispeed(&opt, B9600)  ;cfsetospeed(&opt, B9600);break;
		case   4800: cfsetispeed(&opt, B4800)  ;cfsetospeed(&opt, B4800);break;
		case   2400: cfsetispeed(&opt, B2400)  ;cfsetospeed(&opt, B2400);break;
		default: break;
	}
    
    /*
     * raw mode
     */
    opt.c_lflag   &=   ~(ECHO   |   ICANON   |   IEXTEN   |   ISIG);
    opt.c_iflag   &=   ~(BRKINT   |   ICRNL   |   INPCK   |   ISTRIP   |   IXON);
    opt.c_oflag   &=   ~(OPOST);
    opt.c_cflag   &=   ~(CSIZE   |   PARENB);
    opt.c_cflag   |=   CS8;

    /*
     * 'DATA_LEN' bytes can be read by serial
     */
    opt.c_cc[VMIN]   =   DATA_LEN;                                      
    opt.c_cc[VTIME]  =   150;

    if (tcsetattr(iFd,   TCSANOW,   &opt)<0) {
        return   -1;
    }

    return iFd;
}


void gprs_send_test(int fd)
{
	char tmp[1024];
	int len;
	int  i;

	for(i = 0; i < 16; i++) 
		tmp[i] = i%0xFF;
	
	len = write(fd, tmp, 16);
	
	printf("len = %d
", len); } // *p static int mystrcat(char *p,char *q) { int ret = -1; char *pp = p; ret = (p != NULL) && (q != NULL); if(ret) { while(*pp != '\0') { pp++; } while(*q != '\0') { *(pp++) = *(q++); } *(pp) = '\0'; } return ret; } void gprs_recieve_test1(int fd) { int i = 0; static int len = 0; int readnum = 0; //bzero(read_buf,sizeof(read_buf)); bzero(read_nBytes,sizeof(read_nBytes)); while((readnum = read(fd,read_nBytes,8))>0) { len += readnum; if(readnum == 8) { read_nBytes[readnum] = '\0'; mystrcat(read_buf,read_nBytes); } if(readnum > 0 && readnum < 8) { read_nBytes[readnum] = '\0'; mystrcat(read_buf,read_nBytes); printf("read_buf:%d
", len); printf("read_buf:%s
", read_buf); len = 0; //bzero(read_buf,sizeof(read_buf)); bzero(read_buf,sizeof(read_buf)); } } }

(テストコードはスレッドのwhileサイクルでテストしました)
void *thread_func(void *arg) {
/*ここではargumentタイプの構造体を指すポインタarg_を定義します.thread1 */       //struct argument *arg_thread1;        //arg_thread1=(struct argument *)arg;            while(1)        {              gprs_recieve_test1(fd);              usleep(200);        }            return (void *)123;   }
ここで送信されるリターン改行も文字配列に格納されるため、送信される文字は受信された文字より2つ少ない
シリアル設定部分はここでくどくどしないでネット上はとてもそろっています
次に、実行効果図を示します.