es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿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>

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Descripción del problema

    El usuario es un experto en TI especializado en c++, c, Ubuntu, io y CAN-bus. Tienen un PC/104 que está conectado a dos motores a través de dos adaptadores CAN. Escribieron código en c++ usando la biblioteca libpcanfd 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:

    [16900.914132] pcan: set_normal_mode(CAN1) failed (err -5)
    [16900.914162] pcan: can't open device hardware itself (err -5)!
    

    El usuario buscó el valor -5 en la lista de errores errno 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;

    while (retries < max_retries) {
        fd = pcanfd_open(name, flags, bitrate);
        if (fd >= 0) {
            return fd;
        }
    
        if (errno != EIO) {
            // Ocurrió algún otro error que no está relacionado con E/S.
            // Abortar los reintentos.
            break;
        }
    
        // Ocurrió un error de E/S. Reintentar con espera exponencial.
        retries++;
        timeout_ms = std::min(timeout_ms * 2, max_timeout_ms);
        usleep(timeout_ms * 1000);
    }
    
    return fd;
    

    }


    Esta función intenta abrir el puerto CAN y vuelve a intentar la operación de apertura fallida con retrasos cada vez mayores cuando ocurre un error de E/S. Los argumentos para esta función son los siguientes: * `name`: el nombre del archivo del dispositivo CAN * `flags`: las banderas del dispositivo CAN (por ejemplo, sin bloqueo) * `bitrate`: la velocidad de bits del CAN * `max_retries`: el número máximo de reintentos antes de abandonar * `max_timeout_ms`: el tiempo máximo de espera para el retraso en milisegundos. La función principal modificada puede utilizar esta función `pcanfd_open_retry()` en lugar de la función `pcanfd_open()` para abrir el puerto CAN. ```c++ int main(int argc, char *argv[]) { const char *can_device = "/dev/pcan0"; uint32_t can_flags = OFD_BITRATE | PCANFD_INIT_STD_MSG_ONLY | OFD_NONBLOCKING; uint32_t can_bitrate = 1000000; int max_retries = 5; int max_timeout_ms = 10000; // 10 segundos int fd = -1; fd = pcanfd_open_retry(can_device, can_flags, can_bitrate, max_retries, max_timeout_ms); if (fd < 0) { printf("Open operation failed with err %d on port no. %s\n", fd, can_device); exit(1); } else { printf("Open succeeded with return value %d on port no. %s\n", fd, can_device); } return 0; }

    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.

Comments are closed.