-
-
Notifications
You must be signed in to change notification settings - Fork 70
Expand file tree
/
Copy pathCO_epoll_interface.h
More file actions
307 lines (282 loc) · 9.9 KB
/
CO_epoll_interface.h
File metadata and controls
307 lines (282 loc) · 9.9 KB
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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/**
* 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
* 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 {
/** 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 */
const 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,
const 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 */