У меня проблемы с чтением через последовательный порт на Beaglebone Black с использованием сценария C ++, который я написал. Сценарий отправляет команды и получает ответы от устройства GSM / GPS Adafruit FONA и работает, за исключением того, что между отправкой команд и фактическим получением каких-либо байтов с устройства существует большая задержка (я должен поместить задержку в 1 секунду между писать и читать команды, чтобы получить ответ от устройства). Однако, когда я использую эмулятор последовательного терминала Minicom, между отправкой команды и получением ответа заметной задержки нет. Я предполагаю, что это связано с тем, как я открываю последовательный порт, но я не знаю, что еще я могу изменить. Прямо сейчас у меня есть настройки, настроенные на необработанные режимы ввода и вывода без линейного контроля или эха, но все еще не в состоянии уменьшить время отклика. Любая помощь или идеи приветствуются и приветствуются! Спасибо!
CPP файл:
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <linux/serial.h>
#include <termios.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <stdio.h>
#include "Fona_control.h"
Fona_control::Fona_control(void)
{
begin();
}
void Fona_control::get_gps(void)
{
printf("Reading GPS\n");
unsigned char gpsbuff[250];
memset(gpsbuff,'\0',250);
sleep(0.1);
int bytes_a = 0;
int n_write = write(fona_fd,GPS_GET_DATA,sizeof(GPS_GET_DATA)-1);
sleep(1);
ioctl(fona_fd,FIONREAD,&bytes_a);
printf("Bytes avail: %i\n",bytes_a);
int n_read = read(fona_fd,gpsbuff,bytes_a);
printf("Buffer: %s\n",gpsbuff);
printf("Bytes read: %i\n",n_read);
return;
}void Fona_control::begin(void)
{
printf("FONA Beginning\n");
struct termios oldtio, newtio;
struct serial_struct serinfo;
// Load the pin configuration
/* Open modem device for reading and writing and not as controlling tty
because we don't want to get killed if linenoise sends CTRL-C. */
fona_fd = open(FONA_DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
if (fona_fd < 0) { perror(FONA_DEVICE); exit(-1); }
bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */
/* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
CRTSCTS : output hardware flow control (only used if the cable has
all necessary lines. See sect. 7 of Serial-HOWTO)
CS8 : 8n1 (8bit,no parity,1 stopbit)
CLOCAL : local connection, no modem contol
CREAD : enable receiving characters */
cfsetspeed(&newtio,BAUDRATE_Fona);
newtio.c_cflag |= ( CLOCAL | CREAD );
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |= CS8;
newtio.c_cflag &= ~PARENB;
newtio.c_cflag &= ~CRTSCTS;
newtio.c_cflag &= ~CSTOPB;
newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 1;
ioctl (fona_fd, TIOCGSERIAL, &serinfo);
serinfo.flags |= 0x4000;
ioctl (fona_fd, TIOCSSERIAL, &serinfo);
/* setup for non-canonical mode */
//newtio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | ISTRIP | INLCR | INPCK | ICRNL | IXON | IGNCR);
newtio.c_iflag = 0;
/* Set line flags */
//newtio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
newtio.c_lflag = 0;
/* Raw output
newtio.c_oflag &= ~(OCRNL | ONLCR | ONLRET | ONOCR | ONOEOT| OFILL | OLCUC | OPOST); */
newtio.c_oflag = 0;/* now clean the modem line and activate the settings for the port */
tcflush(fona_fd, TCIOFLUSH);
if(tcsetattr(fona_fd,TCSANOW,&newtio) < 0)
{
printf("Error Setting FONA Serial Port Attributes!");
exit(0);
};
/* terminal settings done, now send FONA initialization commands*/
sleep(1);
unsigned char buffer[50];
int bytes_avail = 0;
int n_write = 0;
int n_read = 0;
int cnt = 0;
memset(buffer,'\0',50);
tcflush(fona_fd, TCIOFLUSH);
while(strstr((char *)buffer,"OK") == NULL && cnt < 5)
{
memset(buffer,'\0',50);
n_write = write(fona_fd,FONA_AT,sizeof(FONA_AT)-1);
sleep(1);
ioctl(fona_fd,FIONREAD,&bytes_avail);
printf("BA: %i\n",bytes_avail);
if(bytes_avail > 0)
{
n_read = read(fona_fd,buffer,bytes_avail);
printf("%s\n",buffer);
}
sleep(1);
cnt++;
}
sleep(1);
n_write = write(fona_fd,"+++",3);
bytes_avail = 0;
sleep(1);
ioctl(fona_fd,FIONREAD,&bytes_avail);
printf("BA2: %i\n",bytes_avail);
n_read = read(fona_fd,buffer,bytes_avail);
printf("%s",buffer);
printf("AT Accepted\n");
sleep(1);
tcflush(fona_fd, TCIOFLUSH);
unsigned char buffer1[50];
memset(buffer1,'\0',50);
int n = write(fona_fd,FONA_ECHO_OFF,sizeof(FONA_ECHO_OFF)-1);
printf("Writ: %i\n",n);
bytes_avail = 0;
sleep(1);
ioctl(fona_fd,FIONREAD,&bytes_avail);
printf("BA2: %i\n",bytes_avail);
n = read(fona_fd,buffer1,bytes_avail);
printf("%s",buffer1);
memset(buffer1,'\0',50);
sleep(1);n = write(fona_fd,GPS_POWER_ON,sizeof(GPS_POWER_ON)-1);
printf("Writ: %i\n",n);
bytes_avail = 0;
sleep(1);
ioctl(fona_fd,FIONREAD,&bytes_avail);
printf("BA2: %i\n",bytes_avail);
n = read(fona_fd,buffer1,bytes_avail);
printf("%s\n",buffer1);
memset(buffer1,'\0',50);
sleep(1);
n = write(fona_fd,FONA_SMS_TYPE,sizeof(FONA_SMS_TYPE)-1);
printf("Writ: %i\n",n);
bytes_avail = 0;
sleep(1);
ioctl(fona_fd,FIONREAD,&bytes_avail);
printf("BA2: %i\n",bytes_avail);
n = read(fona_fd,buffer1,bytes_avail);
printf("%s\n",buffer1);
sleep(1);
}
H файл:
#ifndef _fona_control_H
#define _fona_control_H
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#define FONA_DEVICE "/dev/ttyO5" //Beaglebone Black serial port
//#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define BAUDRATE_Fona B115200 // Change as needed, keep B
/* Define FONA AT Commands */
#define FONA_AT "AT\r\n"#define FONA_ECHO_OFF "ATE0\r\n"#define FONA_CMD_REPEAT "A/\r\n"#define FONA_NO_ECHO "ATE0\r\n"#define FONA_PIN_CHECK "AT+CPIN?\r\n"#define FONA_PIN_SEND "AT+CPIN=1234\r\n"#define FONA_SMS_TYPE "AT+CMGF=1\r\n"
/* Define FONA GPS AT Commands */
#define GPS_POWER_ON "AT+CGNSPWR=1\r\n"#define GPS_POWER_OFF "AT+CGNSPWR=0\r\n"#define GPS_GET_DATA "AT+CGNSINF\r\n"
/* Define FONA GPS NMEA Commands */
#define PMTK_CMD_HOT_START "AT+CGNSCMD=0,"$PMTK101*32"\r\n"#define PMTK_CMD_WARM_START "AT+CGNSCMD=0,"$PMTK102*31"\r\n"#define PMTK_CMD_COLD_START "AT+CGNSCMD=0,"$PMTK103*30"\r\n"#define PMTK_SET_NMEA_5HZ "AT+CGNSCMD=0,"$PMTK220,200*2C"\r\n"#define PMTK_SET_BAUD_38400 "AT+CGNSCMD=0,"$PMTK251,38400*27"\r\n"#define PMTK_SET_WAAS "AT+CGNSCMD=0,"$PMTK301,2*2E"\r\n"#define PMTK_SET_SBAS "AT+CGNSCMD=0,"$PMTK313,1*2E"\r\n"#define PMTK_NMEA_TYPES "AT+CGNSCMD=0,"$PMTK314,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0*29"\r\n"#define PMTK_STANDY_MODE "AT+CGNSCMD=0,"$PMTK161,0*28"\r\n" //Send any byte to exit standby modeclass Fona_control {
public:
void begin(void);
void get_gps(void);
Fona_control(void); // Constructor when using HardwareSerial
uint8_t fix_status, fix_mode, sats, sats_used, glo_sats, cn0;
uint8_t month, day, minute;
uint32_t year;
double seconds, latitude, longitude, speed, course, hdop, vdop, pdop, hpa, vpa;
int fona_fd;
private:};#endif
1 секунда сна убийственна, и я могу заверить вас, миником не делает их. Он будет ожидать поступления данных, а не опроса, а затем отображать их. Последовательные данные работают медленно. Каждому символу, отправляемому со скоростью 9600 бод, требуется около миллисекунды. со скоростью 115,2 кбод вы перемещаете персонажа чуть менее чем за 85 микросекунд. Ваш Beaglebone, с другой стороны, работает в наносекундах, поэтому, если вы не дождетесь чтения, данных еще не будет. Тем не менее, вы должны иметь это «ОК» менее чем за 1 мс, и ждать целую секунду — это излишнее излишество.
Рассмотрим блокировку и ожидание трех байтов, необходимых для «ОК»
while(strstr((char *)buffer,"OK") == NULL && cnt < 5)
{
memset(buffer,'\0',50);
n_write = write(fona_fd,FONA_AT,sizeof(FONA_AT)-1);
n_read = read(fona_fd,buffer,3);
cnt++;
}
Это может заблокировать навсегда, если устройство никогда не отвечает, поэтому вам нужно время ожидания
Самый простой механизм тайм-аута, который я могу себе представить, — это что-то вроде этого:
int retry= 5;
while (retry)
{
fd_set readfs; // file descriptor set used by select
struct timeval timeout;
FD_ZERO(&readfs); // clear file descriptor set
FD_SET(fona_fd, &readfs); // set our port as the one item in the set
timeout.tv_sec = 1;
timeout.tv_usec = 0;
if (select(fona_fd+1, &readfs, NULL, NULL, &timeout) !=0)
{
rval = read(fona_fd, buffer, sizeof(buffer)-1);
// will stop reading after configurable gap between bytes read
buffer[rval] = '\0'; // NULL terminate the buffer or it ain't a string
// If not a string, results of strstr are undefined
if (strstr((char *)buffer,"OK") != NULL)
{
break;
}
}
retry--;
}
Документация по select
. Это очень очень крутая функция. Не так круто, как Эполл, но проще найти учебники для. Если вы делаете много select
дать epoll
хороший взгляд.
Выберите в этом случае будет ждать данные в течение 1 секунды, прежде чем сдаться. Если он найдет данные, программа введет if
тело и read
будет считываться до тех пор, пока не пройдет некоторое настраиваемое пользователем число раз с момента получения последнего символа или до заполнения буфера.
Затем мы завершаем нулевые данные в буфере, чтобы мы могли использовать в нем процедуры обработки строк. Это также устраняет необходимость memset
буфер. Если буфер содержит «ОК», мы выходим из цикла.
В противном случае мы уменьшаем счетчик повторов и зацикливаемся, чтобы увидеть, есть ли еще попытки.
Других решений пока нет …