簡體   English   中英

MacOS 上的 C:通過串行端口的特定讀取始終超時,而所有其他讀取/寫入成功

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM