RTCan missing frames

Johannes Holtz johannes.holtz at compador.de
Mon Feb 11 14:13:47 CET 2019


Am 11.02.19 um 13:40 schrieb Wolfgang Grandegger:
> Hello,
>
> Am 11.02.19 um 12:55 schrieb Johannes Holtz:
>> Am 11.02.19 um 12:26 schrieb Wolfgang Grandegger:
>>> Hello,
>>>
>>> Am 11.02.19 um 10:16 schrieb Johannes Holtz via Xenomai:
>>>> Hi,
>>>>
>>>> In my application i set up a RTCAN socket and a pair of rt-threads. One
>>>> to read and one to write. Writing works perfectly and I receive answers
>>>> in the initial phase of the program.
>>>>
>>>> In particular I send CANopen NMT messages out and receive the responses
>>>> from the other Nodes in the Network.
>>>>
>>>> 2019-02-11 09:52:13.309[       500][    CAN TX] > NMT Node 0:0:
>>>> CAN ID 0x000 FC 0x0 DLC 2
>>>>           0       82 00
>>>> 2019-02-11 09:52:13.310[       503][    CAN RX] > NMT Error Control Node
>>>> 0:8:
>>>> CAN ID 0x708 FC 0xe DLC 1
>>>>           0       00
>>>> 2019-02-11 09:52:13.311[       503][    CAN RX] > NMT Error Control Node
>>>> 0:9:
>>>> CAN ID 0x709 FC 0xe DLC 1
>>>>           0       00
>>>> 2019-02-11 09:52:13.317[       509][    CAN RX] > NMT Error Control Node
>>>> 0:3:
>>>> CAN ID 0x703 FC 0xe DLC 1
>>>>           0       00
>>>> 2019-02-11 09:52:13.317[       509][    CAN RX] > NMT Error Control Node
>>>> 0:4:
>>>> CAN ID 0x704 FC 0xe DLC 1
>>>>           0       00
>>>> 2019-02-11 09:52:13.317[       509][    CAN RX] > NMT Error Control Node
>>>> 0:5:
>>>> CAN ID 0x705 FC 0xe DLC 7
>>>>           0       00 06 07 00
>>>>           4       00 01 01
>>>> 2019-02-11 09:52:13.317[       509][    CAN RX] > NMT Node 0:0:
>>>> CAN ID 0x000 FC 0x0 DLC 3
>>>>           0       07 00 00
>>>> 2019-02-11 09:52:13.326[       519][    CAN RX] > TIME Node 0:1:
>>>> CAN ID 0x101 FC 0x2 DLC 0
>>>>
>>>> As you can see, I capture 7 frames. However, the RX count from
>>>> /proc/rtcan/devices is 10.
>>>>
>>>> If I send specific SDO requests to one of the node which have answered I
>>>> don't capture a response but the RX count increases and rtcanrecv
>>>> program captures the correct response. Only my application's read
>>>> doesn't return.
>>> Then there seem to be a problem with the read in you application. Can
>>> you show use the related code?
>>>
>>> Wolfgang.
>> Here is the main function of the rx thread. This will be executed every
>> 1ms.
>>
>> void can_rx_run(rt_thread_data_t *rt_data) {
>>      can_thread_data_t *data = (can_thread_data_t *) rt_data->data;
>>      data->time++;
>>      static can_frame_t frame_buffer[RX_BUF_SZ];
>>      static can_frame_t *frame   = NULL;
>>      static can_bus_t *bus       = NULL;
>>      int bytes = 1, ret, buf_i = 0;
>>      uint32_t bus_idx = 0;
>>      if ((data->time > 10)&& (data->time%2)) {
>>          bytes       = 1;
>>          for (bus_idx = 0; bus_idx < data->n_buses; bus_idx++) {
>>              bus     = &data->buses[bus_idx];
>>              if(!bus->ready) continue;
>>              while (bytes > 0 && (buf_i<2)) {
>>                  frame   = &frame_buffer[buf_i];
>>                  memset(frame, 0, sizeof (*frame));
>>                  bytes   = rt_dev_recv(bus->socket, frame, sizeof
>> (*frame), MSG_DONTWAIT);
>>                  if (bytes < 0) {
>>                      if ((bytes != -ETIMEDOUT) && (bytes != -EAGAIN)) {
>>                          rtlog(data->log, data->time, LOG_TAG_ERROR,
>> "Connection ended unexpected ret %d errno %d", bytes);
>>                      }else{
>>                          bytes = 1;
>>                      }
>>                      break;
>>                  } else if (bytes == 0) {
>>                      rtlog(data->log, data->time, LOG_TAG_ERROR, "CAN Bus
>> Connection closed by peer");
>>                      break;
>>                  }
>>                  // move pointer forward for the next frame
>>                  buf_i = (buf_i + 1) % RX_BUF_SZ;
>>
>>                  log_frame(data->log, data->time, frame, bus_idx);
>>                  ret = check_frame_integrity(data->log, data->time, frame);
>>                  if (ret) {
>>                      rtlog(data->log, data->time, LOG_TAG_ERROR,
>>                            "Frame didn't pass integrity check %d", ret);
>>                      continue;
>>                  }
>>                  ret = process_frame(data->ipc_socket, frame, bus_idx);
>>                  if (ret < 0) {
>>                      rtlog(data->log, data->time, LOG_TAG_ERROR,
>>                            "failed to accept RX CAN frame %d from Node %u",
>>                            ret);
>>                  }
>>              }
>>          }
>>      }
>> }
> And the code setting up the socket?
>
> Wolfgang.

static int set_bus_mode(can_bus_t* bus, int mode) {
     uint32_t *new_mode = (can_mode_t *) &bus->device.ifr_ifru;
     *new_mode = mode;
     int res = rt_dev_ioctl(bus->socket, SIOCSCANMODE, &bus->device);
     if(res) {
         return CAN_BUS_INIT_ERROR_MODESET;
     }
     return 0;
}

void bus_shutdown (can_bus_t *bus) {

     set_bus_mode(bus, CAN_MODE_STOP);

     if (bus->socket < 0)
         return;

     rt_dev_close (bus->socket);
     bus->socket = -1;

     printf("shutdown bus %d\n", bus->bus_index);
     return;
}

int bus_init (can_bus_t *bus, const int BUS, const uint32_t BAUDRATE, 
const int64_t TIMEOUT_SEND, const int64_t TIMEOUT_RECV) {
     struct sockaddr_can addr;
     bus->bus_index = BUS;
     int res;
     static unsigned int err_mask = CAN_ERR_MASK;
     /*
     static unsigned int err_mask =  CAN_ERR_CRTL         // Controller 
Problems (see data[1])
                                     | CAN_ERR_BUSOFF            // Bus Off
                                     | CAN_ERR_RESTARTED     // 
Controller Restarted
                                     | CAN_ERR_TX_TIMEOUT    // TX 
timeout (netdevice driver).
                                     | CAN_ERR_LOSTARB           // Lost 
arbitration (see data[0]).
                                     | CAN_ERR_PROT        // Protocol 
violations (see data[2], data[3]).
                                     | CAN_ERR_TRX        // Transceiver 
status (see data[4]).
                                     | CAN_ERR_ACK        // Received no 
ACK on transmission.
                                     //| CAN_ERR_BUSERROR        // Bus 
error (may flood!).
                                     //| CAN_ERR_MASK            // All 
error flags.
                                     ;
     */
     // create socket
     bus->socket = rt_dev_socket (PF_CAN, SOCK_RAW, CAN_RAW);
     if (bus->socket < 0) {
         printf("%s > failed to get socket %d\n",__func__, bus->socket);
         return CAN_BUS_INIT_ERROR_RT_DEV_SOCKET;
     }

     // device index
     snprintf (bus->device.ifr_ifrn.ifrn_name, IF_NAMESIZE, "rtcan%d", 
bus->bus_index);
     res = rt_dev_ioctl (bus->socket, SIOCGIFINDEX, &bus->device);
     if (res) {
         printf("%s > failed to set IF name %s error %d\n", __func__, 
bus->device.ifr_ifrn.ifrn_name, res);
         bus_shutdown (bus);
         return CAN_BUS_INIT_ERROR_SIOCGIFINDEX;
     }

     // receive CAN error frames (also pseudo frames)
     res = rt_dev_setsockopt (bus->socket, SOL_CAN_RAW, 
CAN_RAW_ERR_FILTER, &err_mask, sizeof (err_mask));
     if (res) {
         bus_shutdown (bus);
         return CAN_BUS_INIT_ERROR_SETSOCKOPT;
     }

     // bind recv
     addr.can_family     = AF_CAN;
     addr.can_ifindex    = bus->device.ifr_ifindex;
     res = rt_dev_bind (bus->socket, (struct sockaddr *) &addr, sizeof 
(addr));
     if (res < 0) {
         printf("%s > rt_dev_bind failed with %d\n", __func__, res);
         bus_shutdown (bus);
         return CAN_BUS_INIT_ERROR_BIND;
     }

     // baudrate
     can_baudrate_t *baudrate = (can_baudrate_t *) &bus->device.ifr_ifru;
     *baudrate = BAUDRATE;
     res = rt_dev_ioctl (bus->socket, SIOCSCANBAUDRATE, &bus->device);
     if (res) {
         bus_shutdown (bus);
         return CAN_BUS_INIT_ERROR_BAUDRATE;
     }

     // timeout send
     if (TIMEOUT_SEND) {
         res = rt_dev_ioctl (bus->socket, RTCAN_RTIOC_SND_TIMEOUT, 
&TIMEOUT_SEND);
         if (res) {
             bus_shutdown (bus);
             return CAN_BUS_INIT_ERROR_TIMEOUT_SEND;
         }
     }

     // timeout recv
     if (TIMEOUT_RECV) {
         res = rt_dev_ioctl (bus->socket, RTCAN_RTIOC_RCV_TIMEOUT, 
&TIMEOUT_RECV);
         if (res) {
             bus_shutdown (bus);
             return CAN_BUS_INIT_ERROR_TIMEOUT_RECV;
         }
     }

     bus->ready = true;
     return set_bus_mode(bus, CAN_MODE_START);
}





More information about the Xenomai mailing list