[英]C on MacOS: Specific reads over serial port consistently time-out while all other reads/writes succeed
我正在嘗試使用 c99 而不是 .NET 框架啟動並運行edlink-n8的准系統版本,因為我通常不使用 Windows 進行開發。 我能夠使用 getStatus 和 getMode 命令通過串行端口與設備通信,但更復雜的命令(如 fileInfo)在成功寫入后嘗試讀取響應時始終超時。
我已確認該設備在 windows 機器上按預期工作。
這是我的測試代碼:
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
typedef struct {
char * name;
uint32_t size;
uint16_t date;
uint16_t time;
uint8_t attrib;
} fileInfo_t;
int main() {
const char * name = "test/test.nes";
const char * port = "/dev/cu.usbmodem00000000001A1";
int fd = open(port, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open failed (%d): %s\n", errno, strerror(errno));
return 1;
}
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
fprintf(stderr, "tcgetattr failed (%d): %s\n", errno, strerror(errno));
close(fd);
return 1;
}
// % stty -f /dev/cu.usbmodem00000000001A1
// speed 9600 baud;
// lflags: -icanon -isig -iexten -echo
// iflags: -icrnl -ixon -ixany -imaxbel -brkint
// oflags: -opost -onlcr -oxtabs
// cflags: cs8 -parenb
cfmakeraw(&tty);
cfsetspeed(&tty, B9600);
tty.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO);
tty.c_iflag &= ~(ICRNL | IXON | IXANY | IMAXBEL | BRKINT);
tty.c_oflag &= ~(OPOST | ONLCR | OXTABS);
tty.c_cflag &= ~(PARENB | CSIZE);
tty.c_cflag |= (CS8 | CREAD | CLOCAL);
tty.c_cc[VTIME] = 10;
tty.c_cc[VMIN] = 0;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
fprintf(stderr, "tcsetattr failed (%d): %s\n", errno, strerror(errno));
close(fd);
return 1;
}
uint8_t code = 0x10;
uint8_t cmd[4] = { '+', '+' ^ 0xff, code, code ^ 0xff };
uint8_t response[2];
ssize_t w, r;
// Successfully writes 0x10 command to device.
w = write(fd, cmd, 4 * sizeof(uint8_t));
printf("wrote %ld, expected %lu\n", w, 4 * sizeof(uint8_t)); // 4, 4
// Successfully reads 0x00 and 0xa5 status from device.
r = read(fd, response, 2 * sizeof(uint8_t));
printf("read %ld, expected %lu\n", r, 2 * sizeof(uint8_t)); // 2, 2
if (response[1] != 0xa5 || response[0]) {
fprintf(stderr, "Bad status: 0x%02x 0x%02x\n", response[1], response[0]);
close(fd);
return 1;
}
code = 0x11;
cmd[2] = code;
cmd[3] = code ^ 0xff;
// Successfully writes 0x11 command to device.
w = write(fd, cmd, 4 * sizeof(uint8_t));
printf("wrote %ld, expected %lu\n", w, 4 * sizeof(uint8_t)); // 4, 4
// Successfully reads 0xa1 mode from device.
r = read(fd, response, sizeof(uint8_t));
printf("read %ld, expected %lu\n", r, sizeof(uint8_t)); // 1, 1
if (response[0] != 0xa1) {
fprintf(stderr, "Bad mode response: 0x%02x\n", response[0]);
close(fd);
return 1;
}
code = 0xd0;
cmd[2] = code;
cmd[3] = code ^ 0xff;
// Successfully writes 0xd0 command to device.
w = write(fd, cmd, 4 * sizeof(uint8_t));
printf("wrote %ld, expected %lu\n", w, 4 * sizeof(uint8_t)); // 4, 4
uint16_t nameLength = strlen(name);
// Successfully writes nameLength and name to device.
w = write(fd, &nameLength, sizeof(uint16_t));
printf("wrote %ld, expected %lu\n", w, sizeof(uint16_t)); // 2, 2
w = write(fd, name, nameLength * sizeof(char));
printf("wrote %ld, expected %lu\n", w, nameLength * sizeof(char)); // 13, 13
// Fails to read response from device: timeout.
response[0] = 0;
r = read(fd, response, sizeof(uint8_t));
printf("read %ld, expected %lu\n", r, sizeof(uint8_t)); // 0, 1
if (response[0]) {
fprintf(stderr, "Bad fileInfo response: 0x%02x\n", response[0]);
close(fd);
return 1;
}
fileInfo_t fileInfo = { 0 };
// Fails to read file info fields from device: timeout.
r = read(fd, &fileInfo.size, sizeof(uint32_t));
printf("read %ld, expected %lu\n", r, sizeof(uint32_t)); // 0, 4
r = read(fd, &fileInfo.date, sizeof(uint16_t));
printf("read %ld, expected %lu\n", r, sizeof(uint16_t)); // 0, 2
r = read(fd, &fileInfo.time, sizeof(uint16_t));
printf("read %ld, expected %lu\n", r, sizeof(uint16_t)); // 0, 2
r = read(fd, &fileInfo.attrib, sizeof(uint8_t));
printf("read %ld, expected %lu\n", r, sizeof(uint8_t)); // 0, 1
r = read(fd, &nameLength, sizeof(uint16_t));
printf("read %ld, expected %lu\n", r, sizeof(uint16_t)); // 0, 2
fileInfo.name = calloc(nameLength + 1, sizeof(char));
r = read(fd, fileInfo.name, nameLength * sizeof(char));
printf("read %ld, expected %lu\n", r, nameLength * sizeof(char)); // 0, 13
// All fields are still zeroed-out.
printf("%s:\n"
"\tsize: %u\n"
"\tdate: %u\n"
"\ttime: %u\n"
"\tattrib: 0x%02x\n",
fileInfo.name, fileInfo.size, fileInfo.date,
fileInfo.time, fileInfo.attrib);
code = 0x10;
cmd[2] = code;
cmd[3] = code ^ 0xff;
// Successfully writes 0x10 command to device.
w = write(fd, cmd, 4 * sizeof(uint8_t));
printf("wrote %ld, expected %lu\n", w, 4 * sizeof(uint8_t)); // 4, 4
// Successfully reads 0x00 and 0xa5 status from device.
r = read(fd, response, 2 * sizeof(uint8_t));
printf("read %ld, expected %lu\n", r, 2 * sizeof(uint8_t)); // 2, 2
if (response[1] != 0xa5 || response[0]) {
fprintf(stderr, "Bad status: 0x%02x 0x%02x\n", response[1], response[0]);
close(fd);
return 1;
}
free(fileInfo.name);
close(fd);
return 0;
}
我對配置串口不是很熟悉,所以我懷疑這是錯誤所在,但我不確定如何確認這種懷疑。 非常感謝任何建議!
您正在清除 ONLCR 位,但忘記清除 OCRNL 位。 您的文件名長度為 13,恰好是回車的 ASCII 碼,因此您不希望操作系統將該字符轉換為其他字符。
如果您在使用 C 中的串行端口時遇到更多問題,我建議在本文檔的“C 中 Linux 和 macOS 的串行代碼示例”部分中 Pololu 的高質量示例代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.