我正在尝试在 esp-idf 中使用
fgets
从 UART 读取整行。
基本参考代码是选择example。 到目前为止,这是我的代码:
#define DLP_RFID2_BUF_SIZE 256
static char buffer[DLP_RFID2_BUF_SIZE];
uart_config_t uart_config =
{
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_1, DLP_RFID2_BUF_SIZE * 2, 0, 0, NULL, 0));
ESP_ERROR_CHECK(uart_param_config(UART_NUM_1, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(UART_NUM_1, PIN_DLP_RFID2_TX, PIN_DLP_RFID2_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
if ((fd = open("/dev/uart/1", O_RDWR)) == -1)
{
ESP_LOGE(TAG, "Cannot open UART");
return fd;
}
uart_vfs_dev_use_driver(UART_NUM_1);
这里是循环函数:
int s;
fd_set rfds;
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 20000,
};
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
s = select(fd + 1, &rfds, NULL, NULL, &tv);
if (s < 0)
{
ESP_LOGE(TAG, "Select failed: errno %d (%s)", errno, strerror(errno));
}
else if (s == 0)
{
ESP_LOGI(TAG, "Timeout has been reached and nothing has been received");
}
else
{
if (FD_ISSET(fd, &rfds))
{
if (fgets(buffer, sizeof(buffer), ???))
{
// do something
}
}
else
{
ESP_LOGE(TAG, "No FD has been set in select()");
}
}
fgets函数需要一个FILE *
变量作为第三个参数。 但我只有
int
(
fd
,
s
)和
fd_set
(
rfds
)。我尝试更改代码以使用
FILE *
:
FILE *f = fopen("/dev/uart/1", "rw");
// ...
if (fgets(buffer, sizeof(buffer) - 1, f))
{
// do something
}
由于 fgets
阻塞,我需要先检查是否有一些数据。 但现在
select
需要
fd_set
而不是
FILE *
:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
如何将 FILE *
“转换”为
fd_set
或
int
转换为
FILE *
?
select
(2) 使用文件描述符,但需要为
FILE
(3) 使用
fgets
。这里有两种可能性。
给定一个
FILE
对象,您可以使用函数
fileno
来获取相应的文件描述符以在
select
中使用。或者,如果您最初使用
open
(2) 打开文件,以获取文件描述符,您可以使用
fdopen
(3) 从它创建一个
FILE
对象。我在这两种情况下都说“可能”,因为 C 标准中都没有定义
fileno
和 fdopen
,所以如果您处于受限环境中(您提到的 UART 暗示了这一点),它们可能不是可用的。 不过,它们都得到了非常广泛的实现,因此,如果您的库足够大,可以拥有
fgets
,那么它肯定至少会拥有两者之一。