Estou tentando usar fgets
esp-idf para ler uma linha inteira do UART.
O código de referência básico é o exemplo select . Até agora, aqui está meu código:
#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);
aqui a função loop:
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()");
}
}
a função fgets requer uma FILE *
variável como terceiro parâmetro. Mas eu só tenho int
s ( fd
, s
) e fd_set
( rfds
).
Tentei alterar o código para usar FILE *
:
FILE *f = fopen("/dev/uart/1", "rw");
// ...
if (fgets(buffer, sizeof(buffer) - 1, f))
{
// do something
}
já que fgets
está bloqueando preciso verificar se há alguns dados primeiro. Mas agora select
requer um fd_set
e não um FILE *
:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
Como posso "converter" FILE *
para fd_set
ou int
para FILE *
?
Seu problema é que você precisa usar um descritor de arquivo para
select
(2), mas precisa de umFILE
parafgets
(3).Há duas possibilidades aqui.
Dado um
FILE
objeto, você pode usar a funçãofileno
para obter o descritor de arquivo correspondente para uso emselect
.Alternativamente, se você abrir o arquivo inicialmente usando
open
(2), para obter um descritor de arquivo, você poderá usarfdopen
(3) para criar umFILE
objeto a partir dele.Eu digo may em ambos os casos, porque nem
fileno
norfdopen
é definido no padrão C, então se você estiver em um ambiente restrito (o que sua menção de UART sugere) é possível que eles não estejam disponíveis. Eles são ambos amplamente implementados, no entanto, então se sua biblioteca for grande o suficiente para terfgets
, ela certamente terá pelo menos um dos dois.Note que não há garantia de que essas funções funcionarão. O padrão C (2018, Seção 7.21) diz que a
FILE
struct...Portanto, não diz nada sobre descritores de arquivo e, especificamente, não exige que a struct contenha nenhuma informação que permitiria que
fileno
oufdopen
funcionasse. Então , no papel , todas as apostas estão canceladas aqui, e seria bastante legítimo para uma biblioteca C implementarFILE
dessa forma. Mas isso seria incomum na maioria dos contextos C 'normais'.