socketCAN driver:
- Always enable CANptr and timestamp info in CO_CANrx_t. - Update documentation
This commit is contained in:
parent
f21cde9ab0
commit
9d17b0d671
11 changed files with 148 additions and 112 deletions
|
|
@ -129,7 +129,7 @@ extern "C" {
|
||||||
|
|
||||||
#ifdef CO_DOXYGEN
|
#ifdef CO_DOXYGEN
|
||||||
/**
|
/**
|
||||||
* @defgroup CO_NO_OBJ Number of CANopenNode communication objects.
|
* @defgroup CO_NO_OBJ Configuration
|
||||||
*
|
*
|
||||||
* Definitions specify, which and how many CANopenNode communication objects
|
* Definitions specify, which and how many CANopenNode communication objects
|
||||||
* will be used in current configuration. Usage of some objects is mandatory and
|
* will be used in current configuration. Usage of some objects is mandatory and
|
||||||
|
|
|
||||||
2
Doxyfile
2
Doxyfile
|
|
@ -2057,7 +2057,7 @@ PREDEFINED = CO_DOXYGEN \
|
||||||
CO_NO_SDO_CLIENT=1 \
|
CO_NO_SDO_CLIENT=1 \
|
||||||
CO_NO_NMT_MASTER=1 \
|
CO_NO_NMT_MASTER=1 \
|
||||||
CO_NO_LSS_SERVER \
|
CO_NO_LSS_SERVER \
|
||||||
CO_NO_LSS_CLIENT \
|
CO_NO_LSS_CLIENT=1 \
|
||||||
CO_NO_TRACE=1
|
CO_NO_TRACE=1
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ Change Log
|
||||||
- NMT self start functionality (OD object 1F80) implemented to strictly folow standard. Default value for object 1F80 have to be updated in OD editor. See README.md.
|
- NMT self start functionality (OD object 1F80) implemented to strictly folow standard. Default value for object 1F80 have to be updated in OD editor. See README.md.
|
||||||
### Fixed
|
### Fixed
|
||||||
- Various fixes.
|
- Various fixes.
|
||||||
|
- neuberger-socketCAN fixed.
|
||||||
### Added
|
### Added
|
||||||
- CANopen TIME protocol added.
|
- CANopen TIME protocol added.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,9 @@ void CANrx_threadTmr_close(void)
|
||||||
void CANrx_threadTmr_process(void)
|
void CANrx_threadTmr_process(void)
|
||||||
{
|
{
|
||||||
int32_t result;
|
int32_t result;
|
||||||
int32_t i;
|
uint64_t i;
|
||||||
bool_t syncWas;
|
bool_t syncWas;
|
||||||
unsigned long long missed;
|
uint64_t missed;
|
||||||
|
|
||||||
result = CO_CANrxWait(CO->CANmodule[0], threadRT.interval_fd, NULL);
|
result = CO_CANrxWait(CO->CANmodule[0], threadRT.interval_fd, NULL);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
|
|
|
||||||
|
|
@ -33,75 +33,90 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup CO_socketCAN socketCAN
|
* @defgroup CO_socketCAN socketCAN
|
||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* Linux specific interface to CANopenNode
|
* Linux specific interface to CANopenNode
|
||||||
*
|
*
|
||||||
* CANopenNode runs in two threads: timer based realtime thread for CAN receive,
|
* CANopenNode runs in two threads:
|
||||||
* SYNC and PDO and mainline thread for other processing.
|
* - timer based real-time thread for CAN receive, SYNC and PDO, see
|
||||||
|
* CANrx_threadTmr_process()
|
||||||
|
* - mainline thread for other processing, see threadMain_process()
|
||||||
*
|
*
|
||||||
* The "threads" specified here do not fork threads themselves, but require
|
* The "threads" specified here do not fork threads themselves, but require
|
||||||
* that two threads are provided by the calling application.
|
* that two threads are provided by the calling application.
|
||||||
* It uses the global CO object and has one thread-local struct for variables.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize mainline thread.
|
* Initialize mainline thread.
|
||||||
*
|
*
|
||||||
* threadMain is non-realtime thread for CANopenNode processing. It is nonblocking
|
|
||||||
* and should be called cyclically in 50 ms intervals or less if necessary. This
|
|
||||||
* is indicated by the callback function.
|
|
||||||
* This thread processes CO_process() function from CANopen.c file.
|
|
||||||
*
|
|
||||||
* @param callback this function is called to indicate #threadMain_process() has
|
* @param callback this function is called to indicate #threadMain_process() has
|
||||||
* work to do
|
* work to do
|
||||||
* @param object this pointer is given to _callback()_
|
* @param object this pointer is given to _callback()_
|
||||||
*/
|
*/
|
||||||
extern void threadMain_init(void (*callback)(void*), void *object);
|
extern void threadMain_init(void (*callback)(void*), void *object);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup mainline thread.
|
* Cleanup mainline thread.
|
||||||
*/
|
*/
|
||||||
extern void threadMain_close(void);
|
extern void threadMain_close(void);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process mainline thread.
|
* Process mainline thread.
|
||||||
*
|
*
|
||||||
* Function must be called cyclically and after callback
|
* threadMain is non-realtime thread for CANopenNode processing. It is
|
||||||
|
* initialized by threadMain_init(). There is no configuration for CANopen
|
||||||
|
* objects. There is also no configuration for epool or interval timer or notify
|
||||||
|
* pipe. These must be specified externally.
|
||||||
|
*
|
||||||
|
* threadMain_process() calls CO_process() function for processing mainline
|
||||||
|
* CANopen objects. It is non-blocking and should be called cyclically in 50 ms
|
||||||
|
* intervals (typically). Function must also be called immediately after
|
||||||
|
* callback provided in threadMain_init() is called.
|
||||||
*
|
*
|
||||||
* @param reset return value from CO_process() function.
|
* @param reset return value from CO_process() function.
|
||||||
*/
|
*/
|
||||||
extern void threadMain_process(CO_NMT_reset_cmd_t *reset);
|
extern void threadMain_process(CO_NMT_reset_cmd_t *reset);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize realtime thread.
|
* Initialize realtime thread.
|
||||||
*
|
*
|
||||||
* CANrx_threadTmr is realtime thread for CANopenNode processing. It is nonblocking
|
|
||||||
* and must be executed at CAN message receive or periodically in 1ms (or something)
|
|
||||||
* intervals. Inside interval is processed CANopen SYNC message, RPDOs(inputs)
|
|
||||||
* and TPDOs(outputs).
|
|
||||||
* CANrx_threadTmr uses CAN socket from CO_driver.c
|
|
||||||
*
|
|
||||||
* @remark If realtime is required, this thread must be registred as such in the Linux
|
|
||||||
* kernel.
|
|
||||||
*
|
|
||||||
* @param interval_us Interval of periodic timer in microseconds, recommended
|
* @param interval_us Interval of periodic timer in microseconds, recommended
|
||||||
* value for realtime response: 1000 us
|
* value for realtime response: 1000 us
|
||||||
*/
|
*/
|
||||||
extern void CANrx_threadTmr_init(uint32_t interval_us);
|
extern void CANrx_threadTmr_init(uint32_t interval_us);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminate realtime thread.
|
* Terminate realtime thread.
|
||||||
*/
|
*/
|
||||||
extern void CANrx_threadTmr_close(void);
|
extern void CANrx_threadTmr_close(void);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process realtime thread.
|
* Process real-time thread.
|
||||||
*
|
*
|
||||||
* This function must be called inside an infinite loop. It blocks until either
|
* CANrx_threadTmr is realtime thread for CANopenNode processing. It is
|
||||||
* some event happens or a timer runs out.
|
* initialized by CANrx_threadTmr_init(). There is no configuration for CANopen
|
||||||
|
* objects. But configuration for epool event notification facility is included
|
||||||
|
* in CO_CANmodule_init() from CO_driver.c. Epool is configured to monitor the
|
||||||
|
* following file descriptors: notify pipe, CANrx sockets from all interfaces
|
||||||
|
* and interval timer.
|
||||||
|
*
|
||||||
|
* CANrx_threadTmr_process() blocks on epoll_wait(). This is implemented inside
|
||||||
|
* CO_CANrxWait() from CO_driver.c. New CAN message is processed in
|
||||||
|
* CANrx_threadTmr_process() function, which calls CO_process_SYNC(),
|
||||||
|
* CO_process_RPDO() and CO_process_TPDO() functions for each expired timer
|
||||||
|
* interval. This function must be called inside an infinite loop.
|
||||||
|
*
|
||||||
|
* @remark If realtime is required, this thread must be registered as such in
|
||||||
|
* the Linux kernel.
|
||||||
*/
|
*/
|
||||||
extern void CANrx_threadTmr_process();
|
extern void CANrx_threadTmr_process();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
* CANopen Object Dictionary storage object for Linux SocketCAN.
|
* CANopen Object Dictionary storage object for Linux SocketCAN.
|
||||||
*
|
*
|
||||||
* @file CO_OD_storage.h
|
* @file CO_OD_storage.h
|
||||||
* @ingroup CO_socketCAN
|
* @ingroup CO_socketCAN_OD_storage
|
||||||
* @author Janez Paternoster
|
* @author Janez Paternoster
|
||||||
* @copyright 2015 - 2020 Janez Paternoster
|
* @copyright 2015 - 2020 Janez Paternoster
|
||||||
*
|
*
|
||||||
|
|
@ -38,7 +38,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup CO_OD_storage OD_storage
|
* @defgroup CO_socketCAN_OD_storage OD storage
|
||||||
* @ingroup CO_socketCAN
|
* @ingroup CO_socketCAN
|
||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,9 @@
|
||||||
#include <linux/can/error.h>
|
#include <linux/can/error.h>
|
||||||
#include <linux/net_tstamp.h>
|
#include <linux/net_tstamp.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <asm/socket.h>
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "301/CO_driver.h"
|
#include "301/CO_driver.h"
|
||||||
#include "CO_error.h"
|
#include "CO_error.h"
|
||||||
|
|
@ -268,11 +270,9 @@ CO_ReturnError_t CO_CANmodule_init(
|
||||||
rxArray[i].mask = 0xFFFFFFFFU;
|
rxArray[i].mask = 0xFFFFFFFFU;
|
||||||
rxArray[i].object = NULL;
|
rxArray[i].object = NULL;
|
||||||
rxArray[i].CANrx_callback = NULL;
|
rxArray[i].CANrx_callback = NULL;
|
||||||
#ifdef CO_DRIVER_MULTI_INTERFACE
|
|
||||||
rxArray[i].CANptr = NULL;
|
rxArray[i].CANptr = NULL;
|
||||||
rxArray[i].timestamp.tv_sec = 0;
|
rxArray[i].timestamp.tv_sec = 0;
|
||||||
rxArray[i].timestamp.tv_nsec = 0;
|
rxArray[i].timestamp.tv_nsec = 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CO_DRIVER_MULTI_INTERFACE
|
#ifndef CO_DRIVER_MULTI_INTERFACE
|
||||||
|
|
@ -344,7 +344,7 @@ CO_ReturnError_t CO_CANmodule_addInterface(
|
||||||
log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt(ovfl)");
|
log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt(ovfl)");
|
||||||
return CO_ERROR_SYSCALL;
|
return CO_ERROR_SYSCALL;
|
||||||
}
|
}
|
||||||
#ifdef CO_DRIVER_MULTI_INTERFACE
|
|
||||||
/* enable software time stamp mode (hardware timestamps do not work properly
|
/* enable software time stamp mode (hardware timestamps do not work properly
|
||||||
* on all devices)*/
|
* on all devices)*/
|
||||||
tmp = (SOF_TIMESTAMPING_SOFTWARE |
|
tmp = (SOF_TIMESTAMPING_SOFTWARE |
|
||||||
|
|
@ -354,7 +354,6 @@ CO_ReturnError_t CO_CANmodule_addInterface(
|
||||||
log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt(timestamping)");
|
log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt(timestamping)");
|
||||||
return CO_ERROR_SYSCALL;
|
return CO_ERROR_SYSCALL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
//todo - modify rx buffer size? first one needs root
|
//todo - modify rx buffer size? first one needs root
|
||||||
//ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, (void *)&bytes, sLen);
|
//ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, (void *)&bytes, sLen);
|
||||||
|
|
@ -501,11 +500,9 @@ CO_ReturnError_t CO_CANrxBufferInit(
|
||||||
/* Configure object variables */
|
/* Configure object variables */
|
||||||
buffer->object = object;
|
buffer->object = object;
|
||||||
buffer->CANrx_callback = CANrx_callback;
|
buffer->CANrx_callback = CANrx_callback;
|
||||||
#ifdef CO_DRIVER_MULTI_INTERFACE
|
|
||||||
buffer->CANptr = NULL;
|
buffer->CANptr = NULL;
|
||||||
buffer->timestamp.tv_nsec = 0;
|
buffer->timestamp.tv_nsec = 0;
|
||||||
buffer->timestamp.tv_sec = 0;
|
buffer->timestamp.tv_sec = 0;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* CAN identifier and CAN mask, bit aligned with CAN module */
|
/* CAN identifier and CAN mask, bit aligned with CAN module */
|
||||||
buffer->ident = ident & CAN_SFF_MASK;
|
buffer->ident = ident & CAN_SFF_MASK;
|
||||||
|
|
@ -626,7 +623,7 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface(
|
||||||
|
|
||||||
#endif /* CO_DRIVER_MULTI_INTERFACE */
|
#endif /* CO_DRIVER_MULTI_INTERFACE */
|
||||||
|
|
||||||
/******************************************************************************/
|
/* send CAN message ***********************************************************/
|
||||||
static CO_ReturnError_t CO_CANCheckSendInterface(
|
static CO_ReturnError_t CO_CANCheckSendInterface(
|
||||||
CO_CANmodule_t *CANmodule,
|
CO_CANmodule_t *CANmodule,
|
||||||
CO_CANtx_t *buffer,
|
CO_CANtx_t *buffer,
|
||||||
|
|
@ -773,12 +770,12 @@ void CO_CANverifyErrors(CO_CANmodule_t *CANmodule)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/* Read CAN message from socket and verify some errors ************************/
|
||||||
static CO_ReturnError_t CO_CANread(
|
static CO_ReturnError_t CO_CANread(
|
||||||
CO_CANmodule_t *CANmodule,
|
CO_CANmodule_t *CANmodule,
|
||||||
CO_CANinterface_t *interface,
|
CO_CANinterface_t *interface,
|
||||||
struct can_frame *msg,
|
struct can_frame *msg, /* CAN message, return value */
|
||||||
struct timespec *timestamp)
|
struct timespec *timestamp) /* timestamp of CAN message, return value */
|
||||||
{
|
{
|
||||||
int32_t n;
|
int32_t n;
|
||||||
uint32_t dropped;
|
uint32_t dropped;
|
||||||
|
|
@ -838,10 +835,11 @@ static CO_ReturnError_t CO_CANread(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int32_t CO_CANrxMsg(
|
/* find msg inside rxArray and call corresponding CANrx_callback **************/
|
||||||
|
static int32_t CO_CANrxMsg( /* return index of received message in rxArray or -1 */
|
||||||
CO_CANmodule_t *CANmodule,
|
CO_CANmodule_t *CANmodule,
|
||||||
struct can_frame *msg,
|
struct can_frame *msg, /* CAN message input */
|
||||||
CO_CANrxMsg_t *buffer)
|
CO_CANrxMsg_t *buffer) /* If not NULL, msg will be copied to buffer */
|
||||||
{
|
{
|
||||||
int32_t retval;
|
int32_t retval;
|
||||||
const CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */
|
const CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */
|
||||||
|
|
@ -888,9 +886,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff
|
||||||
{
|
{
|
||||||
int32_t retval;
|
int32_t retval;
|
||||||
int32_t ret;
|
int32_t ret;
|
||||||
#ifdef CO_DRIVER_MULTI_INTERFACE
|
|
||||||
const void *CANptr;
|
const void *CANptr;
|
||||||
#endif
|
|
||||||
CO_ReturnError_t err;
|
CO_ReturnError_t err;
|
||||||
CO_CANinterface_t *interface = NULL;
|
CO_CANinterface_t *interface = NULL;
|
||||||
struct epoll_event ev[1];
|
struct epoll_event ev[1];
|
||||||
|
|
@ -938,7 +934,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff
|
||||||
/* one of the sockets is ready */
|
/* one of the sockets is ready */
|
||||||
if ((ev[0].data.fd == CO_NotifyPipeGetFd(CANmodule->pipe)) ||
|
if ((ev[0].data.fd == CO_NotifyPipeGetFd(CANmodule->pipe)) ||
|
||||||
(ev[0].data.fd == fdTimer)) {
|
(ev[0].data.fd == fdTimer)) {
|
||||||
/* timer/pipe socket */
|
/* timer or notify pipe */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -949,10 +945,8 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff
|
||||||
interface = &CANmodule->CANinterfaces[i];
|
interface = &CANmodule->CANinterfaces[i];
|
||||||
|
|
||||||
if (ev[0].data.fd == interface->fd) {
|
if (ev[0].data.fd == interface->fd) {
|
||||||
#ifdef CO_DRIVER_MULTI_INTERFACE
|
|
||||||
/* get interface handle */
|
/* get interface handle */
|
||||||
CANdriverState = interface->CANptr;
|
CANptr = interface->CANptr;
|
||||||
#endif
|
|
||||||
/* get message */
|
/* get message */
|
||||||
err = CO_CANread(CANmodule, interface, &msg, ×tamp);
|
err = CO_CANread(CANmodule, interface, &msg, ×tamp);
|
||||||
if (err != CO_ERROR_NO) {
|
if (err != CO_ERROR_NO) {
|
||||||
|
|
@ -983,16 +977,15 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff
|
||||||
int32_t msgIndex;
|
int32_t msgIndex;
|
||||||
|
|
||||||
#ifdef CO_DRIVER_ERROR_REPORTING
|
#ifdef CO_DRIVER_ERROR_REPORTING
|
||||||
|
/* clear listenOnly and noackCounter if necessary */
|
||||||
CO_CANerror_rxMsg(&interface->errorhandler);
|
CO_CANerror_rxMsg(&interface->errorhandler);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
msgIndex = CO_CANrxMsg(CANmodule, &msg, buffer);
|
msgIndex = CO_CANrxMsg(CANmodule, &msg, buffer);
|
||||||
if (msgIndex > -1) {
|
if (msgIndex > -1) {
|
||||||
#ifdef CO_DRIVER_MULTI_INTERFACE
|
|
||||||
/* Store message info */
|
/* Store message info */
|
||||||
CANmodule->rxArray[msgIndex].timestamp = timestamp;
|
CANmodule->rxArray[msgIndex].timestamp = timestamp;
|
||||||
CANmodule->rxArray[msgIndex].CANptr = CANptr;
|
CANmodule->rxArray[msgIndex].CANptr = CANptr;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
retval = msgIndex;
|
retval = msgIndex;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
/*
|
/**
|
||||||
* Linux socketCAN specific definitions for CANopenNode.
|
* Linux socketCAN specific definitions for CANopenNode.
|
||||||
*
|
*
|
||||||
* @file CO_driver_target.h
|
* @file CO_driver_target.h
|
||||||
|
* @ingroup CO_socketCAN_driver_target
|
||||||
* @author Janez Paternoster
|
* @author Janez Paternoster
|
||||||
* @author Martin Wagner
|
* @author Martin Wagner
|
||||||
* @copyright 2004 - 2020 Janez Paternoster
|
* @copyright 2004 - 2020 Janez Paternoster
|
||||||
|
|
@ -25,15 +26,41 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* This file contains device and application specific definitions.
|
||||||
|
* It is included from CO_driver.h, which contains documentation
|
||||||
|
* for common definitions below. */
|
||||||
|
|
||||||
#ifndef CO_DRIVER_TARGET
|
#ifndef CO_DRIVER_TARGET
|
||||||
#define CO_DRIVER_TARGET
|
#define CO_DRIVER_TARGET
|
||||||
|
|
||||||
/* This file contains device and application specific definitions.
|
#include <stddef.h>
|
||||||
* It is included from CO_driver.h, which contains documentation
|
#include <stdbool.h>
|
||||||
* for definitions below. */
|
#include <stdint.h>
|
||||||
|
#include <endian.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <linux/can.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
/*
|
#if __has_include("CO_driver_custom.h")
|
||||||
* @name multi interface support
|
#include "CO_driver_custom.h"
|
||||||
|
#endif
|
||||||
|
#include "CO_notify_pipe.h"
|
||||||
|
#include "CO_error.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup CO_socketCAN_driver_target CO_driver_target.h
|
||||||
|
* @ingroup CO_socketCAN
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* Linux socketCAN specific @ref CO_driver definitions for CANopenNode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multi interface support
|
||||||
*
|
*
|
||||||
* Enable this to use interface combining at driver level. This
|
* Enable this to use interface combining at driver level. This
|
||||||
* adds functions to broadcast/selective transmit messages on the
|
* adds functions to broadcast/selective transmit messages on the
|
||||||
|
|
@ -51,40 +78,32 @@
|
||||||
* This is not intended to realize interface redundancy!!!
|
* This is not intended to realize interface redundancy!!!
|
||||||
*/
|
*/
|
||||||
/* #define CO_DRIVER_MULTI_INTERFACE */
|
/* #define CO_DRIVER_MULTI_INTERFACE */
|
||||||
|
#ifdef CO_DOXYGEN
|
||||||
|
#define CO_DRIVER_MULTI_INTERFACE
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @name CAN bus error reporting
|
* CAN bus error reporting
|
||||||
*
|
*
|
||||||
* CO_DRIVER_ERROR_REPORTING enabled adds support for socketCAN error detection
|
* CO_DRIVER_ERROR_REPORTING enabled adds support for socketCAN error detection
|
||||||
* and handling functions inside the driver. This is needed when you have
|
* and handling functions inside the driver. This is needed when you have
|
||||||
* CANopen with "0" connected nodes as a use case, as this is normally
|
* CANopen with "0" connected nodes as a use case, as this is normally
|
||||||
* forbidden in CAN.
|
* forbidden in CAN.
|
||||||
*
|
*
|
||||||
* you need to enable error reporting in your kernel driver using
|
* you need to enable error reporting in your kernel driver using:
|
||||||
* "ip link set canX type can berr-reporting on". Of course, the kernel
|
* @code{.sh}
|
||||||
* driver for your hardware needs this functionality to be implemented...
|
* ip link set canX type can berr-reporting on
|
||||||
|
* @endcode
|
||||||
|
* Of course, the kernel driver for your hardware needs this functionality to be
|
||||||
|
* implemented...
|
||||||
*/
|
*/
|
||||||
#ifndef CO_DRIVER_ERROR_REPORTING_DISABLE
|
/* #define CO_DRIVER_ERROR_REPORTING */
|
||||||
|
#ifdef CO_DOXYGEN
|
||||||
#define CO_DRIVER_ERROR_REPORTING
|
#define CO_DRIVER_ERROR_REPORTING
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stddef.h>
|
/* skip this section for Doxygen, because it is documented in CO_driver.h */
|
||||||
#include <stdbool.h>
|
#ifndef CO_DOXYGEN
|
||||||
#include <stdint.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <endian.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <linux/can.h>
|
|
||||||
#include <net/if.h>
|
|
||||||
|
|
||||||
#include "CO_notify_pipe.h"
|
|
||||||
#ifdef CO_DRIVER_ERROR_REPORTING
|
|
||||||
#include "CO_error.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Basic definitions */
|
/* Basic definitions */
|
||||||
#ifdef __BYTE_ORDER
|
#ifdef __BYTE_ORDER
|
||||||
|
|
@ -135,11 +154,9 @@ typedef struct {
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
void *object;
|
void *object;
|
||||||
void (*CANrx_callback)(void *object, void *message);
|
void (*CANrx_callback)(void *object, void *message);
|
||||||
#ifdef CO_DRIVER_MULTI_INTERFACE
|
const void *CANptr; /* CAN Interface identifier from last
|
||||||
/* info about last received message */
|
message */
|
||||||
const void *CANptr; /* CAN Interface identifier */
|
struct timespec timestamp; /* time of reception of last message */
|
||||||
struct timespec timestamp; /* time of reception */
|
|
||||||
#endif
|
|
||||||
} CO_CANrx_t;
|
} CO_CANrx_t;
|
||||||
|
|
||||||
/* Transmit message object as aligned in socketCAN. */
|
/* Transmit message object as aligned in socketCAN. */
|
||||||
|
|
@ -182,7 +199,8 @@ typedef struct {
|
||||||
volatile bool_t CANnormal;
|
volatile bool_t CANnormal;
|
||||||
void *em;
|
void *em;
|
||||||
CO_NotifyPipe_t *pipe; /* Notification Pipe */
|
CO_NotifyPipe_t *pipe; /* Notification Pipe */
|
||||||
int fdEpoll; /* epoll FD */
|
int fdEpoll; /* epoll FD for pipe, CANrx sockets in all
|
||||||
|
interfaces and fdTimerRead */
|
||||||
int fdTimerRead; /* timer handle from CANrxWait() */
|
int fdTimerRead; /* timer handle from CANrxWait() */
|
||||||
#ifdef CO_DRIVER_MULTI_INTERFACE
|
#ifdef CO_DRIVER_MULTI_INTERFACE
|
||||||
/* Lookup tables Cob ID to rx/tx array index.
|
/* Lookup tables Cob ID to rx/tx array index.
|
||||||
|
|
@ -221,9 +239,11 @@ static inline void CO_UNLOCK_OD() {
|
||||||
#define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;}
|
#define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;}
|
||||||
#define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;}
|
#define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;}
|
||||||
|
|
||||||
|
#endif /* CO_DOXYGEN */
|
||||||
|
|
||||||
|
|
||||||
#ifdef CO_DRIVER_MULTI_INTERFACE
|
#ifdef CO_DRIVER_MULTI_INTERFACE
|
||||||
/*
|
/**
|
||||||
* Add socketCAN interface to can driver
|
* Add socketCAN interface to can driver
|
||||||
*
|
*
|
||||||
* Function must be called after CO_CANmodule_init.
|
* Function must be called after CO_CANmodule_init.
|
||||||
|
|
@ -236,7 +256,7 @@ static inline void CO_UNLOCK_OD() {
|
||||||
CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule,
|
CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule,
|
||||||
const void *CANptr);
|
const void *CANptr);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Check on which interface the last message for one message buffer was received
|
* Check on which interface the last message for one message buffer was received
|
||||||
*
|
*
|
||||||
* It is in the responsibility of the user to check that this information is
|
* It is in the responsibility of the user to check that this information is
|
||||||
|
|
@ -256,7 +276,7 @@ bool_t CO_CANrxBuffer_getInterface(CO_CANmodule_t *CANmodule,
|
||||||
const void **const CANptrRx,
|
const void **const CANptrRx,
|
||||||
struct timespec *timestamp);
|
struct timespec *timestamp);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Set which interface should be used for message buffer transmission
|
* Set which interface should be used for message buffer transmission
|
||||||
*
|
*
|
||||||
* It is in the responsibility of the user to ensure that the correct interface
|
* It is in the responsibility of the user to ensure that the correct interface
|
||||||
|
|
@ -277,26 +297,33 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface(CO_CANmodule_t *CANmodule,
|
||||||
#endif /* CO_DRIVER_MULTI_INTERFACE */
|
#endif /* CO_DRIVER_MULTI_INTERFACE */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Functions receives CAN messages. It is blocking.
|
* Functions receives CAN messages (blocking)
|
||||||
*
|
*
|
||||||
* This function can be used in two ways
|
* This function waits for received CAN message, CAN error frame, notification
|
||||||
* - automatic mode (call callback that is set by #CO_CANrxBufferInit() function)
|
* pipe or fdTimer expiration. In case of CAN message it searches _rxArray_ from
|
||||||
* - manual mode (evaluate message filters, return received message)
|
* CO_CANmodule_t and if matched it calls the corresponding CANrx_callback,
|
||||||
|
* optionally copies received CAN message to _buffer_ and returns index of
|
||||||
|
* matched _rxArray_.
|
||||||
*
|
*
|
||||||
* Both modes can be combined.
|
* This function can be used in two ways, which can be combined:
|
||||||
|
* - automatic mode: If CANrx_callback is specified for matched _rxArray_, then
|
||||||
|
* calls its callback.
|
||||||
|
* - manual mode: evaluate message filters, return received message
|
||||||
*
|
*
|
||||||
* @param CANmodule This object.
|
* @param CANmodule This object.
|
||||||
* @param fdTimer file descriptor with activated timeout. fd is not read after
|
* @param fdTimer File descriptor with activated timeout. If set to -1, then
|
||||||
* expiring! -1 if not used.
|
* timer will not be used. File descriptor must be read
|
||||||
* @param buffer [out] storage for received message or _NULL_
|
* externally if retval == -1! Read must be nonblocking and
|
||||||
* @retval >= 0 index of received message in array set by #CO_CANmodule_init()
|
* provides number of timer expirations since last read.
|
||||||
* _rxArray_, copy available in _buffer_
|
* @param [out] buffer Storage for received message or _NULL_ if not used.
|
||||||
* @retval -1 no message received
|
* @retval >= 0 index of received message in array from CO_CANmodule_t
|
||||||
|
* _rxArray_, copy of CAN message is available in _buffer_.
|
||||||
|
* @retval -1 no message received (timer expired or notification pipe or error)
|
||||||
*/
|
*/
|
||||||
int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule,
|
int32_t CO_CANrxWait(CO_CANmodule_t* CANmodule, int fdTimer, CO_CANrxMsg_t* buffer);
|
||||||
int fdTimer,
|
|
||||||
CO_CANrxMsg_t *buffer);
|
/** @} */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
#include <linux/can/error.h>
|
#include <linux/can/error.h>
|
||||||
|
|
||||||
#include "301/CO_driver.h"
|
#include "301/CO_driver.h"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
* CANopenNode Linux socketCAN Error handling.
|
* CANopenNode Linux socketCAN Error handling.
|
||||||
*
|
*
|
||||||
* @file CO_error.h
|
* @file CO_error.h
|
||||||
* @ingroup CO_socketCAN
|
* @ingroup CO_socketCAN_ERROR
|
||||||
* @author Martin Wagner
|
* @author Martin Wagner
|
||||||
* @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH
|
* @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH
|
||||||
*
|
*
|
||||||
|
|
@ -41,11 +41,11 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup CO_socketCAN_ERROR socketCAN_ERROR
|
* @defgroup CO_socketCAN_ERROR CAN errors & Log
|
||||||
* @ingroup CO_socketCAN
|
* @ingroup CO_socketCAN
|
||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* CANopen Errors and logging of messages
|
* CANopen Errors and System message log
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -108,9 +108,7 @@ typedef enum {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int fd; /**< interface FD */
|
int fd; /**< interface FD */
|
||||||
char ifName[IFNAMSIZ]; /**< interface name as string */
|
char ifName[IFNAMSIZ]; /**< interface name as string */
|
||||||
|
uint32_t noackCounter; /**< counts no ACK on CAN transmission */
|
||||||
uint32_t noackCounter;
|
|
||||||
|
|
||||||
volatile unsigned char listenOnly; /**< set to listen only mode */
|
volatile unsigned char listenOnly; /**< set to listen only mode */
|
||||||
struct timespec timestamp; /**< listen only mode started at this time */
|
struct timespec timestamp; /**< listen only mode started at this time */
|
||||||
} CO_CANinterfaceErrorhandler_t;
|
} CO_CANinterfaceErrorhandler_t;
|
||||||
|
|
@ -143,7 +141,8 @@ void CO_CANerror_disable(
|
||||||
/**
|
/**
|
||||||
* Message received event
|
* Message received event
|
||||||
*
|
*
|
||||||
* when a message is received at least one other CAN module is connected
|
* When a message is received at least one other CAN module is connected.
|
||||||
|
* Function clears listenOnly and noackCounter error flags.
|
||||||
*
|
*
|
||||||
* @param CANerrorhandler CAN error object.
|
* @param CANerrorhandler CAN error object.
|
||||||
*/
|
*/
|
||||||
|
|
@ -154,7 +153,7 @@ void CO_CANerror_rxMsg(
|
||||||
/**
|
/**
|
||||||
* Check if interface is ready for message transmission
|
* Check if interface is ready for message transmission
|
||||||
*
|
*
|
||||||
* message musn't be transmitted if not ready
|
* Message mustn't be transmitted if not ready.
|
||||||
*
|
*
|
||||||
* @param CANerrorhandler CAN error object.
|
* @param CANerrorhandler CAN error object.
|
||||||
* @return CO_INTERFACE_ACTIVE message transmission ready
|
* @return CO_INTERFACE_ACTIVE message transmission ready
|
||||||
|
|
@ -166,7 +165,7 @@ CO_CANinterfaceState_t CO_CANerror_txMsg(
|
||||||
/**
|
/**
|
||||||
* Error message received event
|
* Error message received event
|
||||||
*
|
*
|
||||||
* this handles all received error messages
|
* This handles all received error messages.
|
||||||
*
|
*
|
||||||
* @param CANerrorhandler CAN error object.
|
* @param CANerrorhandler CAN error object.
|
||||||
* @param msg received error message
|
* @param msg received error message
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
* Notify pipe for Linux threads.
|
* Notify pipe for Linux threads.
|
||||||
*
|
*
|
||||||
* @file CO_notify_pipe.h
|
* @file CO_notify_pipe.h
|
||||||
* @ingroup CO_socketCAN
|
* @ingroup CO_socketCAN_notify_pipe
|
||||||
* @author Martin Wagner
|
* @author Martin Wagner
|
||||||
* @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH
|
* @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH
|
||||||
*
|
*
|
||||||
|
|
@ -32,7 +32,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup CO_pipe Pipe
|
* @defgroup CO_socketCAN_notify_pipe Notify pipe
|
||||||
* @ingroup CO_socketCAN
|
* @ingroup CO_socketCAN
|
||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue