¿Por qué Ubuntu arroja un error de E/S al azar?
Tengo un PC/104 (con sistema operativo Ubuntu 16.04 y kernel 4.19.89 xenomai3) conectado a dos motores a través de dos adaptadores CAN. Hace unos días, escribí un código simple para abrir los puertos CAN de mi PC/104 usando la biblioteca libpcanfd.
Mi carpeta de proyecto sigue la siguiente jerarquía:
- io_error_debug
- build
- include (vacío)
- src
- CMakeLists.txt
- main.cpp
- CMakeLists.txt
El archivo CMakeLists.txt está ubicado en /root y contiene lo siguiente:
cmake_minimum_required(VERSION 2.6)
project(io_error_debug)
include_directories(${PROJECT_SOURCE_DIR}/include) # add before adding subdirectory
add_subdirectory (src)
add_executable(io_error_debug src/main.cpp)
target_link_libraries(io_error_debug /usr/lib/libpcanfd.so # pcan
"-Wl,--no-as-needed -Wl,@/usr/xenomai/lib/cobalt.wrappers -Wl,@/usr/xenomai /lib/modechk.wrappers /usr/xenomai/lib/xenomai/bootstrap-pic.o -L/usr/xenomai/lib -lcobalt -lmodechk -lpthread -lrt"
)
El archivo CMakeLists.txt en la carpeta src contiene lo siguiente:
aux_source_directory(. SRC_LIST)
El archivo main.cpp contiene:
#include <sys time.h="">
#include <lcm lcm_coretypes.h="">
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys mman.h="">
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
#include <sys syscall.h="">
#include <pcanfd.h>
#include <libpcanfd.h>
#include <cmath>
#include <iostream>
int main(int argc, char *argv[]){
int fd;
fd = pcanfd_open("/dev/pcan0", OFD_BITRATE | PCANFD_INIT_STD_MSG_ONLY | OFD_NONBLOCKING, 1000000);
if (fd < 0)
{
printf("Open operation failed with err %d on port no. /dev/pcan0\n",fd);
exit(1);
}else{
printf("Open succeeded with return value %d on port no. /dev/pcan0\n",fd);
}
}
El código se compila y se ejecuta correctamente cuando los motores están encendidos. Sin embargo, cuando apago los motores y los vuelvo a encender, obtengo el siguiente error después de ejecutar mi código:
Open operation failed with err -5 on port no. /dev/pcan0
Además, dmesg muestra estas líneas de error sospechosas cuando ejecuto mi código:
[16900.914132] pcan: set_normalmode(CAN1) failed (err -5)
[16900.914162] pcan: can't open device hardware itself (err -5)!
La documentación indica que -5 es un error de errno. Por lo tanto, busqué el valor -5 en esta lista de errores errno y descubrí que es un error de E/S. Curiosamente, cuando apago el PC/104 y ejecuto mi código, el programa funciona bien. Sin embargo, cuando repito la operación mencionada anteriormente (es decir, apagando y encendiendo los motores), volveré a encontrar el mismo error. No entiendo lo que está sucediendo.</libpcanfd.h></pcanfd.h></errno.h></pthread.h></signal.h></fcntl.h></unistd.h></inttypes.h></stdlib.h></stdio.h></math.h>
davy.ai
Descripción del problema
El usuario es un experto en TI especializado en
c++
,c
,Ubuntu
,io
yCAN-bus
. Tienen un PC/104 que está conectado a dos motores a través de dos adaptadores CAN. Escribieron código enc++
usando la bibliotecalibpcanfd
para abrir los puertos CAN del PC/104.El código se compila y se ejecuta correctamente cuando los motores están encendidos. Sin embargo, cuando los motores se apagan y luego se encienden nuevamente, el usuario obtiene un mensaje de error que dice
Open operation failed with err -5 on port no. /dev/pcan0
.dmesg
muestra algunas líneas de error sospechosas cuando se ejecuta el código:El usuario buscó el valor
-5
en la lista de erroreserrno
y descubrieron que es un “error de E/S”. Curiosamente, cuando el PC/104 está apagado y se ejecuta su código, el programa funciona correctamente. Pero cuando se enciende el PC/104 nuevamente, ocurre el mismo error.Solución
El mensaje de error
Open operation failed with err -5
sugiere un error de E/S. Este error ocurre cuando hay un problema al leer o escribir en un archivo o dispositivo. En este caso, parece haber un problema con el adaptador CAN del PC/104 cuando los motores se apagan y luego se encienden nuevamente.Una posible solución a este problema es volver a intentar la operación de apertura fallida utilizando una estrategia de espera exponencial. La función
pcanfd_open()
se puede modificar para volver a intentar la operación de apertura fallida con un retraso que aumenta exponencialmente después de cada falla. El retraso se puede limitar a un valor máximo de tiempo de espera para evitar que se produzcan intentos de reintentos infinitos.“`c++
int pcanfd_open_retry(const char *name, uint32_t flags, uint32_t bitrate, int max_retries, int max_timeout_ms) {
int fd = -1;
int retries = 0;
int timeout_ms = 1;
}
Este código modificado intenta abrir el puerto CAN usando la función
pcanfd_open_retry()
, que reintentará la operación de apertura con una espera exponencial si ocurre un error de E/S. El número de reintentos y el tiempo máximo de espera para el retraso se pueden ajustar para adaptarse a los requisitos específicos de la aplicación del usuario.Al utilizar la estrategia de espera exponencial, el código puede recuperarse del error de E/S provocado por el adaptador CAN cuando los motores se apagan y luego se encienden nuevamente.