ОБНОВЛЕНО: Как узнать, когда полудуплексная последовательная линия станет свободной? - PullRequest
2 голосов
/ 06 июня 2019

У меня есть фактический последовательный порт на основе RS-232, который я использую с Linux для беспроводной связи с микроконтроллером. (Я использую беспроводные модули на обоих концах соединения вместо последовательного кабеля)

Есть одна проблема. Вся операция должна быть полудуплексной, потому что беспроводные модули не поддерживают полнодуплексную работу. На самом деле они игнорируют входящие данные при отправке данных.

Таким образом, в C я ищу наиболее эффективный и быстрый код, который можно обнаружить, когда нет данных, поступающих от удаленного передатчика, прежде чем начать отправку кода обратно на пульт.

Кроме того, удаленное устройство дает мне всего 30 мсек для отправки данных обратно, а сами данные - 47 байтов, а скорость - 56 Кбит / с, поэтому процедура обнаружения молчания на линии должна выполняться быстро.

Я предоставил некоторые идеи, но я пытаюсь выяснить, что лучше. Может быть, есть функция, о которой я даже не знаю, которая работает еще лучше. Я экспериментировал с разными значениями VMIN и VTIME и оказался неуспешным.

Вот мои идеи кода:

Идея 1:

  char b[2]; //incoming character buffer
  int nread=1; //number of bytes read

  int fd=open(dev,O_NOCTTY | O_RDONLY | O_SYNC);
  while (nread > 0){
    nread=read(fd,b,1); //keep reading until no bytes read are reported
  }
  fclose(fd);

Идея 2:

  int timeout=1; //1 second timeout
  int fd=open(dev,O_NOCTTY | O_RDONLY | O_SYNC);
  time_t then=time(NULL);
  while (time(NULL) - then > timeout){
    nread=read(fd,b,1); 
    if (nread > 0){then=time(NULL);} //reset timer if at least 1 byte is read
  }
  fclose(fd);

Идея 3:

  char b[2]; //incoming character buffer
  int nread=1; //number of bytes read
  int numfail=0; //number of failed attempts to read bytes
  int fd=open(dev,O_NOCTTY | O_RDONLY | O_SYNC);
  while (numfail < 100){
    nread=read(fd,b,1); //keep reading until no bytes read are reported 100 consecutive times
    if (nread < 1){numfail++;}else{numfail=0;}
  }
  fclose(fd);

Первая идея, которая, вероятно, не сработает (разве мне не повезет найти здесь специальную конфигурацию драйвера linux?), Будет продолжать проверять порт на один байт, пока ни один не будет найден, а затем завершится.

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

Последняя идея является расширением первой идеи, за исключением того, что программа не будет завершена, пока не будут завершены несколько последовательных попыток чтения одного байта из последовательной строки. Счетчик попыток сбрасывается, если обнаружен хотя бы один байт. Я чувствую, что это может быть моим лучшим выбором наряду с использованием лучших настроек VTIME и VMIN, но я не уверен.

Мне просто нужна функция, которая может тратить очень мало времени (не более многих микросекунд), чтобы определить, когда данные не передаются по последовательной линии каким-либо устройством.

Единственное решение, которое у меня есть на данный момент, - это создание большего количества оборудования, которое собирает последовательные данные с ПК, буферизует данные, а затем оборудование определяет, когда последовательная линия свободна, перед отправкой данных на удаленное устройство, но я не хочу тратить больше печатных плат и деталей. Я бы предпочел иметь программное решение (в Linux).

Есть идеи?

И для ясности, удаленное устройство использует микроконтроллер на базе 8052 (модель at89S52) с UART, имеющим только 1-байтовый кеш, а мой компьютер использует 16550 UART, и я думаю, что он имеет 14 или 16-байтовый кеш.

UPDATE

Я попробовал другую идею, которая несколько лучше. Кажется, он обнаруживает изменения, когда линия свободна или не свободна с интервалом 2 мс, но я пытаюсь обнаружить больше на микросекундном уровне.

Это мой код:

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
  #include <fcntl.h>
  #include <sys/select.h>

  int main(int argc, char* argv[]){
    int fd=open("/dev/ttyS0",O_NOCTTY | O_RDONLY | O_SYNC);
    if (fd < 0){
        printf("Error\n");
        return -1;
    }
    long v=1;
    if (argc > 1){
      v=strtol(argv[1],NULL,10); //Custom inter-string timeout
    }
    struct timeval t={0,5000}; //set initial timeout to 5mS
    int gotsz=0; //characters received total
    int bpsz=100000; //Most # characters we want
    unsigned char b[bpsz]; //characters
    unsigned char* bp=b; //Active pointer to characters
    bpsz--; //We don't want to wreck memory that isnt ours
    fd_set f; 
    while(1){
      FD_ZERO(&f);
      FD_SET(fd,&f);
      int ret=select(fd+1,&f,NULL,NULL,&t); //check at 5mS intervals for anything
      if (ret < 0){
        printf("Error\n");
        return -1;
      }
      if (ret != 0){
        break; //Stall until anything is received.
      }
    }
    while(1){
      FD_ZERO(&f);
      FD_SET(fd,&f);
      int ret=select(fd+1,&f,NULL,NULL,&t);
      if (ret < 0){
        printf("Error\n");
        return -1;
      }
      if (ret == 0){
        break;    //Only exit loop when there are no more characters in a short time
      }
      int sz=read(fd,bp,bpsz); //fill up buffer advancing start pointer (saves use of strcpy)
      gotsz+=sz;
      bp+=sz;
      bpsz-=sz;
      t.tv_usec=v;
    }
    close(fd);
    //print all that we got in hex
    bp=b;
    printf("Got: ");
    int n;
    for (n=0;n<gotsz;n++){
        printf("%X",*bp);
        bp++;
    }
    printf("\n");
    printf("Intermediate Timeout %ld uS (%ld mS)\n",v,v/1000);
    return 0;
  }

Теперь я чувствую, что мне нужно создавать какую-то глобальную системную блокировку каждый раз, когда я хочу прочитать данные с последовательного порта, чтобы определить, когда данные читаются. Под этим я подразумеваю, если, например, я использую свой компьютер для нескольких целей, таких как просмотр веб-страниц и воспроизведение музыки в фоновом режиме или просмотр видео, и я запускаю свою программу, я думаю, заставляя мою программу заморозить все вышеупомянутые процессы только для чтения последовательных Данные порта дадут процессору достаточно времени для обработки данных последовательного порта. Затем, когда моя программа заканчивается, процессы могут возобновиться.

Есть идеи, как мне этого добиться?

...