309 lines
9.9 KiB
C
309 lines
9.9 KiB
C
/**
|
|
* Helper functions for Linux epoll interface to CANopenNode.
|
|
*
|
|
* @file CO_epoll_interface.h
|
|
* @ingroup CO_epoll_interface
|
|
* @author Janez Paternoster
|
|
* @author Martin Wagner
|
|
* @copyright 2004 - 2020 Janez Paternoster
|
|
* @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH
|
|
*
|
|
*
|
|
* This file is part of CANopenNode, an opensource CANopen Stack.
|
|
* Project home page is <https://github.com/CANopenNode/CANopenNode>.
|
|
* For more information on CANopen see <http://www.can-cia.org/>.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef CO_EPOLL_INTERFACE_H
|
|
#define CO_EPOLL_INTERFACE_H
|
|
|
|
#include "CANopen.h"
|
|
|
|
#include <sys/epoll.h>
|
|
#include <sys/eventfd.h>
|
|
#include <sys/timerfd.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @defgroup CO_socketCAN socketCAN
|
|
* @{
|
|
*
|
|
* Linux specific interface to CANopenNode.
|
|
*
|
|
* Linux includes CAN interface inside its kernel, so called SocketCAN. It
|
|
* operates as a network device. For more information on Linux SocketCAN see
|
|
* https://www.kernel.org/doc/html/latest/networking/can.html
|
|
*
|
|
* Linux specific files for interfacing with Linux SocketCAN are located inside
|
|
* "CANopenNode/socketCAN" directory.
|
|
*
|
|
* CANopenNode runs as a set of non-blocking functions. It can run in single or
|
|
* multiple threads. Best approach for RT IO device can be with two threads:
|
|
* - timer based real-time thread for CAN receive, SYNC and PDO, see
|
|
* @ref CO_epoll_processRT()
|
|
* - mainline thread for other processing, see @ref CO_epoll_processMain()
|
|
*
|
|
* Main references for Linux functions used here are Linux man pages and the
|
|
* book: The Linux Programming Interface by Michael Kerrisk.
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @defgroup CO_epoll_interface Epoll interface
|
|
* @ingroup CO_socketCAN
|
|
* @{
|
|
*
|
|
* Linux epoll interface to CANopenNode.
|
|
*
|
|
* The Linux epoll API performs a monitoring multiple file descriptors to see
|
|
* if I/O is possible on any of them.
|
|
*
|
|
* CANopenNode uses epoll interface to provide an event based mechanism. Epoll
|
|
* waits for multiple different events, such as: interval timer event,
|
|
* notification event, CAN receive event or socket based event for gateway.
|
|
* CANopenNode non-blocking functions are processed after each event.
|
|
*
|
|
* CANopenNode itself offers functionality for calculation of time, when next
|
|
* interval timer event should trigger the processing. It can also trigger
|
|
* notification events in case of multi-thread operation.
|
|
*/
|
|
|
|
/**
|
|
* Object for epoll, timer and event API.
|
|
*/
|
|
typedef struct {
|
|
/** Epoll file descriptor */
|
|
int epoll_fd;
|
|
/** Notification event file descriptor */
|
|
int event_fd;
|
|
/** Interval timer file descriptor */
|
|
int timer_fd;
|
|
/** Interval of the timer in microseconds, from @ref CO_epoll_create() */
|
|
uint32_t timerInterval_us;
|
|
/** Time difference since last @ref CO_epoll_wait() execution in
|
|
* microseconds */
|
|
uint32_t timeDifference_us;
|
|
/** Timer value in microseconds, which can be changed by application and can
|
|
* shorten time of next @ref CO_epoll_wait() execution */
|
|
uint32_t timerNext_us;
|
|
/** True,if timer event is inside @ref CO_epoll_wait() */
|
|
bool_t timerEvent;
|
|
/** time value from the last process call in microseconds */
|
|
uint64_t previousTime_us;
|
|
/** Structure for timerfd */
|
|
struct itimerspec tm;
|
|
/** Structure for epoll_wait */
|
|
struct epoll_event ev;
|
|
/** true, if new epoll event is necessary to process */
|
|
bool_t epoll_new;
|
|
} CO_epoll_t;
|
|
|
|
/**
|
|
* Create Linux epoll, timerfd and eventfd
|
|
*
|
|
* Create and configure multiple Linux notification facilities, which trigger
|
|
* execution of the task. Epoll blocks and monitors multiple file descriptors,
|
|
* timerfd triggers in constant timer intervals and eventfd triggers on external
|
|
* signal.
|
|
*
|
|
* @param ep This object
|
|
* @param timerInterval_us Timer interval in microseconds
|
|
*
|
|
* @return @ref CO_ReturnError_t CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or
|
|
* CO_ERROR_SYSCALL.
|
|
*/
|
|
CO_ReturnError_t CO_epoll_create(CO_epoll_t *ep, uint32_t timerInterval_us);
|
|
|
|
/**
|
|
* Close epoll, timerfd and eventfd
|
|
*
|
|
* @param ep This object
|
|
*/
|
|
void CO_epoll_close(CO_epoll_t *ep);
|
|
|
|
/**
|
|
* Wait for an epoll event
|
|
*
|
|
* This function blocks until event registered on epoll: timerfd, eventfd, or
|
|
* application specified event. Function also calculates timeDifference_us since
|
|
* last call and prepares timerNext_us.
|
|
*
|
|
* @param ep This object
|
|
*/
|
|
void CO_epoll_wait(CO_epoll_t *ep);
|
|
|
|
/**
|
|
* Closing function for an epoll event
|
|
*
|
|
* This function must be called after @ref CO_epoll_wait(). Between them
|
|
* should be application specified processing functions, which can check for
|
|
* own events and do own processing. Application may also lower timerNext_us
|
|
* variable. If lowered, then interval timer will be reconfigured and
|
|
* @ref CO_epoll_wait() will be triggered earlier.
|
|
*
|
|
* @param ep This object
|
|
*/
|
|
void CO_epoll_processLast(CO_epoll_t *ep);
|
|
|
|
/**
|
|
* Initialization of functions in CANopen reset-communication section
|
|
*
|
|
* Configure callbacks for CANopen objects.
|
|
*
|
|
* @param ep This object
|
|
* @param co CANopen object
|
|
*/
|
|
void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co);
|
|
|
|
/**
|
|
* Process CANopen mainline functions
|
|
*
|
|
* This function calls @ref CO_process(). It is non-blocking and should execute
|
|
* cyclically. It should be between @ref CO_epoll_wait() and
|
|
* @ref CO_epoll_processLast() functions.
|
|
*
|
|
* @param ep This object
|
|
* @param co CANopen object
|
|
* @param enableGateway If true, gateway to external world will be enabled.
|
|
* @param [out] reset Return from @ref CO_process().
|
|
*/
|
|
void CO_epoll_processMain(CO_epoll_t *ep,
|
|
CO_t *co,
|
|
bool_t enableGateway,
|
|
CO_NMT_reset_cmd_t *reset);
|
|
|
|
|
|
/**
|
|
* Process CAN receive and realtime functions
|
|
*
|
|
* This function checks epoll for CAN receive event and processes CANopen
|
|
* realtime functions: @ref CO_process_SYNC(), @ref CO_process_RPDO() and
|
|
* @ref CO_process_TPDO(). It is non-blocking and should execute cyclically.
|
|
* It should be between @ref CO_epoll_wait() and @ref CO_epoll_processLast()
|
|
* functions.
|
|
*
|
|
* Function can be used in the mainline thread or in own realtime thread.
|
|
*
|
|
* Processing of CANopen realtime functions is protected with @ref CO_LOCK_OD.
|
|
* Also Node-Id must be configured and CANmodule must be in CANnormal for
|
|
* processing.
|
|
*
|
|
* @param ep Pointer to @ref CO_epoll_t object.
|
|
* @param co CANopen object
|
|
* @param realtime Set to true, if function is called from the own realtime
|
|
* thread, and is executed at short constant interval.
|
|
*/
|
|
void CO_epoll_processRT(CO_epoll_t *ep,
|
|
CO_t *co,
|
|
bool_t realtime);
|
|
|
|
|
|
#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN
|
|
/**
|
|
* Command interface type for gateway-ascii
|
|
*/
|
|
typedef enum {
|
|
CO_COMMAND_IF_DISABLED = -100,
|
|
CO_COMMAND_IF_STDIO = -2,
|
|
CO_COMMAND_IF_LOCAL_SOCKET = -1,
|
|
CO_COMMAND_IF_TCP_SOCKET_MIN = 0,
|
|
CO_COMMAND_IF_TCP_SOCKET_MAX = 0xFFFF
|
|
} CO_commandInterface_t;
|
|
|
|
/**
|
|
* Object for gateway
|
|
*/
|
|
typedef struct {
|
|
/** Epoll file descriptor, from @ref CO_epoll_createGtw() */
|
|
int epoll_fd;
|
|
/** Command interface type or tcp port number, see
|
|
* @ref CO_commandInterface_t */
|
|
int32_t commandInterface;
|
|
/** Socket timeout in microseconds */
|
|
uint32_t socketTimeout_us;
|
|
/** Socket timeout timer in microseconds */
|
|
uint32_t socketTimeoutTmr_us;
|
|
/** Path in case of local socket */
|
|
char *localSocketPath;
|
|
/** Gateway socket file descriptor */
|
|
int gtwa_fdSocket;
|
|
/** Gateway io stream file descriptor */
|
|
int gtwa_fd;
|
|
/** Indication of fresh command */
|
|
bool_t freshCommand;
|
|
} CO_epoll_gtw_t;
|
|
|
|
/**
|
|
* Create socket for gateway-ascii command interface and add it to epoll
|
|
*
|
|
* Depending on arguments function configures stdio interface or local socket
|
|
* or IP socket.
|
|
*
|
|
* @param epGtw This object
|
|
* @param epoll_fd Already configured epoll file descriptor
|
|
* @param commandInterface Command interface type from CO_commandInterface_t
|
|
* @param socketTimeout_ms Timeout for established socket connection in [ms]
|
|
* @param localSocketPath File path, if commandInterface is local socket
|
|
*
|
|
* @return @ref CO_ReturnError_t CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or
|
|
* CO_ERROR_SYSCALL.
|
|
*/
|
|
CO_ReturnError_t CO_epoll_createGtw(CO_epoll_gtw_t *epGtw,
|
|
int epoll_fd,
|
|
int32_t commandInterface,
|
|
uint32_t socketTimeout_ms,
|
|
char *localSocketPath);
|
|
|
|
/**
|
|
* Close gateway-ascii sockets
|
|
*
|
|
* @param epGtw This object
|
|
*/
|
|
void CO_epoll_closeGtw(CO_epoll_gtw_t *epGtw);
|
|
|
|
/**
|
|
* Initialization of gateway functions in CANopen reset-communication section
|
|
*
|
|
* @param epGtw This object
|
|
* @param co CANopen object
|
|
*/
|
|
void CO_epoll_initCANopenGtw(CO_epoll_gtw_t *epGtw, CO_t *co);
|
|
|
|
/**
|
|
* Process CANopen gateway functions
|
|
*
|
|
* This function checks for epoll events and verifies socket connection timeout.
|
|
* It is non-blocking and should execute cyclically. It should be between
|
|
* @ref CO_epoll_wait() and @ref CO_epoll_processLast() functions.
|
|
*
|
|
* @param epGtw This object
|
|
* @param co CANopen object
|
|
* @param ep Pointer to @ref CO_epoll_t object.
|
|
*/
|
|
void CO_epoll_processGtw(CO_epoll_gtw_t *epGtw,
|
|
CO_t *co,
|
|
CO_epoll_t *ep);
|
|
#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */
|
|
|
|
/** @} */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif /*__cplusplus*/
|
|
|
|
#endif /* CO_EPOLL_INTERFACE_H */
|