Использование select () и fgets () для доступа к информации через последовательный порт - PullRequest
2 голосов
/ 13 июля 2011

Это продолжение этого вопроса: Как ждать ввода от последовательного порта в середине программы

Я пишу программу для управления модемом Iridium, которая должна ждать ответа от последовательного порта в середине программы, чтобы убедиться, что был получен правильный ответ. Для этого пользователь рекомендовал использовать команду select() для ожидания ввода.

Однако я столкнулся с некоторыми трудностями при таком подходе. Первоначально select() будет возвращать значение, указанное в ответе, каждый раз, когда ответ (хотя модем отправлял обратно правильные ответы, что я проверял с другой программой, запущенной в то же время). Теперь программа останавливается после одной итерации, даже если правильный ответ отправлен с модема.

 //setting the file descriptor to the port
int fd = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);

if (fd == -1)
{
  /*
   * Could not open the port.
   */

  perror("open_port: Unable to open /dev/ttyS0 - ");
}
else
 fcntl(fd, F_SETFL, 0);

FILE *out = fopen(portName.c_str(), "w");//sets the serial port
FILE *in = fopen(portName.c_str(), "r");


fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
struct timeval timeout = { 10, 0 }; /* 10 seconds */
//int ret = select(fd+1, &fds, NULL, NULL, &timeout);
/* ret == 0 means timeout, ret == 1 means descriptor is ready for reading,
 ret == -1 means error (check errno) */

char buf[100];

int i =0; 
while(i<(sizeof(messageArray)/sizeof(messageArray[0])))
{
  //creates a string with the AT command that writes to the module
  std::string line1("AT+SBDWT=");
  line1+=convertInt( messageArray[i].numChar);
  line1+=" ";
  line1+=convertInt(messageArray[i].packetNumber);
  line1+=" ";
  line1+=messageArray[i].data;
  line1+=std::string("\r\n");

  //creates a string with the AT command that initiates the SBD session
  std::string line2("AT+SBDI");
  line2+=std::string("\r\n");

  fputs(line1.c_str(), out); //sends to serial port

  //usleep(7000000);     
  int ret =select(fd+1, &fds, NULL, NULL, &timeout);
  /* ret == 0 means timeout, ret == 1 means descriptor is ready for reading,
 ret == -1 means error (check errno) */

  if (ret ==1){
fgets (buf ,sizeof(buf), in);
//add code to check if response is correct
  }
  else if(ret == 0) {
perror("timeout error ");
  }
  else if (ret ==-1) {
perror("some other error");
  }

  fputs(line2.c_str(), out); //sends to serial port

  //usleep(7000000); //Pauses  between the addition of each packet.
  int ret2 = select(fd+1, &fds, NULL, NULL, &timeout);
  /* ret == 0 means timeout, ret == 1 means descriptor is ready for reading,
 ret == -1 means error (check errno) */

  if(ret2 == 0) {
perror("timeout error ");
  }
  else if (ret2 ==-1) {
perror("some other error");
  }

  i++;
}

Ответы [ 2 ]

3 голосов
/ 13 июля 2011

Вы не используете один и тот же дескриптор файла для чтения / записи / выбора, что несколько странно.

Вы не сбрасываете свои fd_sets, которые были изменены с помощью select, и в случае тайм-аута все ваши fds были бы сброшены, по умолчанию тайм-аут следующего вызова (так как вы запрашиваете отсутствие fds).

вы также используете буферизованный ввод-вывод, который в этом случае обязательно вызовет головную боль. например. fgets ожидает либо EOF (что не произойдет), либо символ новой строки, читая все время. Он будет блокироваться до тех пор, пока не получит новую строку, поэтому может держать вас зависать бесконечно, если этого не произойдет Он также может прочитать больше, чем нужно, в буфер, испортив ваш сигнал select чтения (у вас есть данные в буфере, но выбор истечет, так как нечего читать в дескрипторе файла).

Итог таков:

  • используйте FD_SET в цикле для установки / сброса ваших наборов fd, также сбросьте время ожидания, так как select может изменить его.
  • использовать один дескриптор для чтения / записи / выбора вместо нескольких дескрипторов, например. открыть файл с fopen(..., "w+") или open(..., O_RDWR)
  • если все еще используется fopen, попробуйте отключить буферизацию с помощью setvbuf с параметром буферизации _IONBF.
  • в противном случае используйте open / read / write вместо fopen и т. Д.

Отмечу, что часть этого была упомянута в этом ответе на ваш предыдущий вопрос.

0 голосов
/ 13 июля 2011

Возможно, вам следует использовать fflush () в потоке выходного файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...