Ведущие нулевые байты последовательного USB от Arduino Teensy с использованием termios - PullRequest
0 голосов
/ 07 ноября 2019

У меня есть одноплатный Odroid Neo4, который подключен через USB к Teensy 4.0. Я пытаюсь отправлять 4 КБ буфера за раз от подростка до neo4 шорт без знака (я понимаю, что в конечном итоге это просто передача необработанных байтов). Я получаю 256 байтов (или 128 шортов) ведущих нулей на каждый полученный буфер 4 КБ. Этот проект включает в себя датчик, собирающий данные, которые выполняется подростком, а сейчас я пытаюсь просто отправить значения 0 - 2047 (4 Кб подсчета шорт).

Подросток запускает код arduinoэтот Serial.write (buffer [4096])) при запуске каждые 5 секунд, и я проверил с labview, что он успешно отправляет данные. Код C на Neo4 открывает последовательный порт с перечисленными ниже параметрами. Я перепробовал множество конфигураций, найденных в интернете, и после прочтения справочной страницы linux, а также нескольких других ресурсов на termios в итоге использовал неканонические параметры, найденныездесь: http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html с небольшими изменениями. Из того, что я обнаружил, использование termios в неканоническом режиме зависит от VTIME и VMIN, потому что я не хочу пропустить точку данных с моего датчика, которую я выбрал, чтобы использовать VTIME = 0, VMIN = 0, не используямеж-символьный таймер, а не блокировка. Я создал 2 буфера: один для чтения 256 байт, а второй - 4 КБ для постепенного копирования меньшего буфера до его полного заполнения, а затем просто его печати. Проблема, с которой я столкнулся при рассмотрении, заключается в том, что при печати каждого большого буфера размером 4 Кбайт первый буфер размером 256 байт представляет собой все нули. Не имея возможности найти проблему, я исправил это, просто сдвинув свой буфер размером 4 Кбайт на 256 байт, что работает, но не объясняет причину этой проблемы и является скорее успешным устранением ошибок, чем эффективной функцией.

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

'''
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h> 
#include <unistd.h>
#include <string.h>

#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyACM0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1

//small buffer size
#define BUFSIZE 256

//offset determined by the mysterious 127 shorts of leading zeros
#define OFFSET 256

volatile int STOP=FALSE; 

int main()
{
    int fd,c, res;
    struct termios oldtio,newtio;
    unsigned char buf[BUFSIZE];

    fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY); 
    if (fd <0) {perror(MODEMDEVICE); exit(-1); }

    tcgetattr(fd,&oldtio); /* save current port settings */

    bzero(&newtio, sizeof(newtio));
    newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
    newtio.c_iflag = IGNPAR;
    newtio.c_oflag = 0; //&= ~OPOST; 

    /* set input mode (non-canonical, no echo,...) */
    newtio.c_lflag = 0;

    newtio.c_cc[VTIME]    = 0;   /* inter-character timer unused */
    newtio.c_cc[VMIN]     = 0;   /* not blocking read*/ 

    tcflush(fd, TCIOFLUSH);
    tcsetattr(fd,TCSANOW,&newtio);

    int total = 0;
    //allocating extra offset so I can allow the extra zeros on the front 
    and still get my 4kb buffer
    unsigned char* buf1 = malloc(4096 + OFFSET);
    unsigned char* pos = buf1;

    while (STOP==FALSE) 
    {       /* loop for input */
        res = read(fd,buf,BUFSIZE);   /* returns after 255 chars have been 
    input */

        //the buffer position increments by res (read)
        if (res > 0)
        {
            pos += res;
            //cpy buf to whereever pos is at res amount
            memcpy(pos,buf,res);
            total += res;
            //printf("total: %d\n", res);
        }
        //once 4kb buffer (+offset) is full
        if (total >= 4096)
        {
            printf("%d b buffer: ",total);
            //start late because of leading zeros
            unsigned short * ps = buf1 + 256;

            //adjust pointer because of off by 1 byte
            // unsigned char* cs = ps;
            // cs++;
            // ps = cs;

            //print 4kb of shorts
            for (int i = 0; i < (4096/2); i++, ps++)
            { 
                printf("%d ", *ps);
            }
            printf("\n\n");
            pos = buf1;
            total = 0;
        }
    }
    tcsetattr(fd,TCSANOW,&oldtio);
    return 0;
}
'''

ВЫХОД:

'''


     4096 b buffer: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 
//...continues to increment normally...
1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 

    4096 b buffer: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 
//...continues to increment normally...
1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 

        ^C
'''

1 Ответ

0 голосов
/ 08 ноября 2019

[Этот ответ был составлен для исходного размещенного вопроса, который с тех пор был пересмотрен в различных деталях. Основная ошибка осталась прежней.]

... закончились использованием неканонических настроек, найденных здесь: http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html с несколькими небольшими изменениями.

Вы выбрали неверно, и у вас есть код инициализации termios, который не является надежным.
Он может работать сегодня в вашей нынешней системе, но этот код может не переноситься в другую систему.
См. Настройка терминалаПравильный режим .


A: почему я получаю 254 байта начальных нулей в моем первом буфере и как этого избежать,

Ваш кодчтение с последовательного терминала имеет несколько недостатков.

    res = read(fd,buf,BUFSIZE);   /* returns after 255 chars have been input */

    //the buffer position increments by res (read)
    if (res > 0)
    {
        pos += res;
        //cpy buf to whereever pos is at res amount
        memcpy(pos,buf,res);
        total += res;
    }

Ваш код (в целом) не проверяет возможные ошибки от системных вызовов.

Если предположить, что первое read () прошло успешно, тогда в вашем буфере будет возвращено 255 байтов buf, и res будет иметь значение 255.
Перед копированием полученных данных с buf на buf1 ваша программа преждевременно обновляет указатель назначения pos на счетчик приема.
Это начало «смещения» на что вы жалуетесь.

Указатель pos должен обновляться после операции копирования, а не раньше.


B: почемумой ввод всегда отключен одним байтом.

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

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


IOW "254 байта старших нулей" плюс "отключение одним байтом" равно 255 количество байтов, возвращаемое начальными значениями read () .


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

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


Обратите внимание, что ваш код генерирует предупреждения компилятора:

test.c: In function ‘main’:
test.c:72:35: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
             unsigned short * ps = buf1 + OFFSET;
                                   ^
test.c:75:33: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
             unsigned char* cs = ps;
                                 ^
test.c:77:16: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
             ps = cs;

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


ADDENDUM к пересмотренному вопросу

Пересмотр вашего кода значения VMIN проблематичен по нескольким причинам.

Это проблематично для эффективности во время выполнения, потому что VMIN = 0 и VTIME = 0 настраивают последовательный терминал для формы неблокирующих операций чтения.
Согласно этому руководству такая конфигурация должна быть толькоиспользуется, когда «Вы действительно, действительно знаете, что делаете» .

Анализ вашей ошибки кодирования проблематичен.
На основании вашего пересмотренного отчета о том, что "offset" теперь составляет 256 байтов (вместо 255), я должен предположить, что выручное инициирование передающей программы перед этой принимающей программой.
Это даст достаточно времени для последовательной передачи и заполнения буфера терминала. (См. Размер FIFO программного обеспечения BeagleBone Black UART? )
Следовательно, начальное значение read () для 256 байтов может быть полностью удовлетворено, поскольку (исходный) буфер терминала уже заполнен даннымиготов к «чтению».
Это «полное» чтение в сочетании с ошибкой вашей программы сохраняет эти данные со смещением 256 байт.

Если вы инициируете эту принимающую программу перед передающей программой, то фактическое смещение копии, созданное ошибкой, подвержено изменениям обработки.
Но независимо от значения смещения причина всегда одна и та же (т. Е. указатель назначения для копии преждевременно обновляется).

...