-
-
Notifications
You must be signed in to change notification settings - Fork 53
/
CO_epoll_interface.h
251 lines (228 loc) · 9.53 KB
/
CO_epoll_interface.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/**
* 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 <https://github.com/CANopenNode/CANopenNode>, a CANopen Stack.
*
* 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
* Linux epoll interface to CANopenNode.
*
* @ingroup CO_socketCAN
* @{
* 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 {
int epoll_fd; /**< Epoll file descriptor */
int event_fd; /**< Notification event file descriptor */
int timer_fd; /**< Interval timer file descriptor */
uint32_t timerInterval_us; /**< Interval of the timer in microseconds, from @ref CO_epoll_create() */
uint32_t timeDifference_us; /**< Time difference since last @ref CO_epoll_wait() execution in microseconds */
uint32_t timerNext_us; /**< Timer value in microseconds, which can be changed by application and can shorten
time of next @ref CO_epoll_wait() execution */
bool_t timerEvent; /**< True,if timer event is inside @ref CO_epoll_wait() */
uint64_t previousTime_us; /**< time value from the last process call in microseconds */
struct itimerspec tm; /**< Structure for timerfd */
struct epoll_event ev; /**< Structure for epoll_wait */
bool_t epoll_new; /**< true, if new epoll event is necessary to process */
} 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 {
int epoll_fd; /**< Epoll file descriptor, from @ref CO_epoll_createGtw() */
int32_t commandInterface; /**< Command interface type or tcp port number, see @ref CO_commandInterface_t */
uint32_t socketTimeout_us; /**< Socket timeout in microseconds */
uint32_t socketTimeoutTmr_us; /**< Socket timeout timer in microseconds */
char* localSocketPath; /**< Path in case of local socket */
int gtwa_fdSocket; /**< Gateway socket file descriptor */
int gtwa_fd; /**< Gateway io stream file descriptor */
bool_t freshCommand; /**< Indication of fresh command */
} 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 */