Надежный валидатор данных последовательного порта для Linux
Я пытаюсь написать программу для Linux, которая проверяет, что данные представляют собой определенную последовательность байтов следующим образом:
1st byte: Sender Identification (should be FAh)
2nd byte: System identification (should be CDh but isn't)
3rd through 6th byte: Raw data (trying to get 40h, 41h 42h and 43h for my test)
7th byte and 8th byte: fletcher-16 checksum of 1st 6 bytes.
Удаленное устройство представляет собой схему, в которой используется микроконтроллер AT89C4051, и оба настроены на скорость передачи 57,6 кбит / с.
Я провел несколько тестов.
Когда я использовал приведенный ниже код, я часто получал следующий набор байтов в виде шестнадцатеричных значений:
FA 50 A8 11 D7 65 BF 2E
Но когда я запустил следующую команду:
screen /dev/ttyS0 57600
и проверил данные на экране, это выглядело точно. Затем я вышел из экрана и побежал
od -tx1 -w8 -v /dev/ttyS0
И выходные данные там выглядят более точными, чем те, которые выдает моя программа. Фактически, по крайней мере 6 из 8 байтов показаны в правильном порядке.
Есть ли что-то, что я могу изменить в своем коде ниже, чтобы мне не приходилось выполнять экранную команду, выходить из нее и выполнять команды od все время, чтобы увидеть больше действительных данных? (В частности, я стараюсь избегать ручного вычисления контрольной суммы данных)
Сейчас давайте предположим, что устройства подключены через короткий физический последовательный кабель и что оба они включены без прерывания питания.
//SERIAL + checksum
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <poll.h>
int setopts(int speed,char* dev){
struct termios options;
int fd = open(dev, O_RDWR | O_NOCTTY | O_SYNC);
if (fd<0){
printf("ERROR opening %s. %s\n",dev,strerror(errno));
return -1;
}
fcntl(fd, F_SETFL, FNDELAY);
memset(&options,0,sizeof options);
tcflush(fd,TCIOFLUSH);
tcgetattr(fd,&options);
cfsetispeed(&options, speed);
cfsetospeed(&options, speed);
//Trying to turn off flow control
options.c_iflag = IGNBRK | IGNPAR; //raw input
options.c_cflag |= (TOSTOP|NOFLSH|CLOCAL|CREAD|CS8);//ignore modem + parity: 8N1 + no rtscts
options.c_lflag=0; //raw input
options.c_oflag=0;options.c_cc[VMIN]=100;options.c_cc[VTIME]=2; //raw output
tcsetattr(fd, TCSANOW, &options);
close(fd);
return 0;
}
int main(int argc,char* argv[]){
unsigned char rstr[200];
memset(rstr,0,199); //rstr=raw string passed to/from serial cable
char dev[1000];
memset(dev,0,999); //dev=path to serial port
strcpy(dev,argv[2]);
//them=8-bit remote ID
//me=8-bit ID of me
//spd=baud
unsigned int them=strtoul(argv[5],NULL,10),me=strtoul(argv[4],NULL,10);
unsigned long spd=strtoul(argv[3],NULL,10);
if (dev[0] != '/'){
memcpy(dev,"/dev/ttyS0",10);
printf("WARNING: No serial device specified. Using /dev/ttyS0\n");
}
if (spd < 1200){
spd=1200;
printf("WARNING: invalid baud specified. Using 1200bps\n");
}
if (them > 255){them=2;}
if (me > 255){me=1;}
printf("ME=%02X, THEM=%02X Speed=%lu\n",me,them,spd);
if (setopts(spd,dev) != 0){return -1;}
if (op[0]=='r'){
int fd = open(dev, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0){
printf("ERROR: Can't open port\n");
return -1;
}
printf("Trying to get all bytes...\n");
char b[5]; //tiny buffer for byte read
int bb=0;
for (bb=0;bb<8;bb++){
while(read(fd,b,1) < 1){} //Lock up over zero bytes is desired
rstr[bb]=b[0]; //Copy bytes 1 by 1 as read
}
close(fd);
unsigned char sum1=0,sum2=0; //fletchers checksum
int n;
for (n=0;n<6;n++){
sum1+=rstr[n];sum2+=sum1;
}
if (rstr[6]==sum1 && rstr[7]==sum2){
printf("Checksum OK\n");
}else{
printf("BAD checksum. Expected %02X%02X got %02X%02X\n",sum1,sum2,rstr[6],rstr[7]);
}
printf("Receipient check: ");
if (rstr[1]==(unsigned char)me){
printf("OK\n");
}else{
printf("BAD. Expected: %02X got %02X\n",me,rstr[1]);
}
printf("Raw data: ");
for (n=0;n<8;n++){
printf("%02X ",rstr[n]);
}
printf("\n");
}
return 0;
}