Я пытаюсь подключить бесконтактный считыватель смарт-карт через UART (usbserial), используя среду termios под Linux. Код отлично работает на ПК, но когда я кросс-компилирую и пробую его на цели ARM9, он может открыть устройство и даже записать команду на устройство, но команда чтения блокируется на неопределенный срок. Вот фрагмент кода:
int mifare_rdr_init(struct mifare_1K * ptr, char *rdr_devnode)
{
bzero(ptr, sizeof(struct mifare_1K)); // zero the entire structure
// open serial device
int fd = open(rdr_devnode, O_RDWR|O_NOCTTY );
if (fd == -1) {
perror("Failed to open serial device ");
return 1;
}
ptr->serialfd = fd; // save file descriptor
ptr->serialdev.c_iflag = 0; // no i/p flags
ptr->serialdev.c_oflag = 0; // o/p flags
ptr->serialdev.c_cflag = ( CS8 | CREAD | B38400 ); // 8 bits, receive enable, baud for rdr
ptr->serialdev.c_lflag = ( ICANON ); // CANONICAL mode, means read till newline char '\n'.
// control chars
// commented below line as suggested by A.H below, since it's not needed in CANONICAL mode
// ptr->serialdev.c_cc[VMIN] = 1; // read unblocks only after at least one received char.
// flush all i/o garbage data if present
tcflush(ptr->serialfd,TCIOFLUSH);
int ret = 0;
// apply settings
ret = tcsetattr(ptr->serialfd,TCSANOW,&ptr->serialdev);
if (ret == -1) {
perror("tcsetattr() failed ");
return 2;
}
return 0;
}
int get_mifare_rdr_version(struct mifare_1K *ptr, char *data)
{
// flush all i/o garbage data if present
tcflush(ptr->serialfd,TCIOFLUSH);
int chars_written = write(ptr->serialfd,"$1V\n",4);
if( chars_written < 0 ) {
perror("Failed to write serial device ");
return 1;
}
printf("cmd sent, read version...\n"); // this prints, so I know cmd sent...
int chars_read = read(ptr->serialfd,ptr->data_buf,14);
if( chars_read < 0 ) {
perror("Failed to read serial device ");
return 2;
}
// copy data to user buffer
printf("reading done.\n"); // this doesn't print...
return 0;
}
Структура mifare_1K содержит дескриптор файла для последовательного устройства, структуру termios и различные буферы, которые я использую. Устройство, как я упоминал, является устройством usb-to-serial (module: ftdi_sio). Он настроен на 38400 @ 8-N-1 в каноническом режиме termios.
Канонический режим, потому что ответы считывателя заканчиваются на '\ n', поэтому его лучше обрабатывать в каноническом режиме, поскольку он читает устройство до получения '\ n' (пожалуйста, исправьте меня, если я ошибаюсь).
Сначала я вызываю init () fn, а затем get_rdr_version (). Строка «cmd sent, read version ...» напечатана, поэтому я знаю, что она умеет писать, но не печатает строку «read done». после этого.
Другое дело, что если я удалю кард-ридер и подключу этот порт к gtkterm (терминальной программе последовательного порта) на другом ПК, я не получу «$ 1V \ n» на этом gtkterm ?? !! , Затем, после небольшого RnD, я обнаружил, что если я перезагружаю систему, к которой подключен считыватель, тогда только я получаю этот cmd «$ 1V \ n» на другом Gtkterm. Если я попытаюсь снова без перезагрузки, этот cmd не будет виден на этом Gkterm ... подсказка, но он еще не разобрался.
Это что-то вроде того, что cmd записывается в файл устройства, но не сливается на реальное устройство? Есть ли способ проверить это?
Любая помощь высоко ценится, так как я застрял на этом некоторое время ... спасибо.
ОБНОВЛЕНИЕ:
Хорошо, у меня все получилось, немного изменив код, как показано ниже.
// open serial device
int fd = open(rdr_devnode, O_RDWR|O_NOCTTY|O_NDELAY ); // O_NDELAY ignores the status of DCD line, all read/write calls after this will be non-blocking
fcntl(fd,F_SETFL,0); // restore read/write blocking behavior
if (fd == -1) {
perror("Failed to open serial device ");
return 1;
}
Это модифицированный раздел кода, который открывает порт в моей функции init (). Два изменения:
1) O_NDELAY добавляется к флагам в вызове open (), который игнорирует линию Data Carrier Detect (DCD), чтобы увидеть, подключен ли другой конец и готов ли он к связи или нет. Первоначально он использовался для модемов, которые мне не нужны, на самом деле у меня его нет вообще, поскольку я использую usbserial. Но этот флаг также делает дальнейшие вызовы read () и write () неблокирующими. Обратите внимание: я думал, что об этом позаботятся, добавив CLOCAL в cflag struct termios, что я пробовал, но не сработало.
2) fcntl (fd, F_SETFL, 0) восстанавливает поведение блокировки дальнейших вызовов read () и write ().
Это комбо отлично работает для меня. Причина only , которую я не публикую в качестве ответа, заключается в том, что я еще не понимаю, почему он работал на ПК без этой модификации, поскольку это было то же аппаратное обеспечение. Фактически, я смог прочитать данные с устройства чтения смарт-карт на ARM9 TARGET, используя minicom , но не мою программу. Я собираюсь проверить документацию FT232BL, чтобы узнать, каков статус DCD по умолчанию.
В любом случае, я нашел этот бит информации в Руководство по последовательному программированию для операционных систем POSIX . Объяснение кому-нибудь ??? Конечно, я выложу ответ, когда узнаю.
Приветствия:)