Lely core libraries 1.9.2
nmt_hb.c
Go to the documentation of this file.
1
24#include "nmt_hb.h"
25#include "co.h"
26#include <lely/co/dev.h>
27#include <lely/util/diag.h>
28
29#include <assert.h>
30#include <stdlib.h>
31
43 co_unsigned8_t id;
45 co_unsigned8_t st;
47 co_unsigned16_t ms;
52 int state;
53};
54
60static int co_nmt_hb_recv(const struct can_msg *msg, void *data);
61
67static int co_nmt_hb_timer(const struct timespec *tp, void *data);
68
69void *
70__co_nmt_hb_alloc(void)
71{
72 void *ptr = malloc(sizeof(struct __co_nmt_hb));
73 if (__unlikely(!ptr))
74 set_errc(errno2c(errno));
75 return ptr;
76}
77
78void
79__co_nmt_hb_free(void *ptr)
80{
81 free(ptr);
82}
83
84struct __co_nmt_hb *
85__co_nmt_hb_init(struct __co_nmt_hb *hb, can_net_t *net, co_nmt_t *nmt)
86{
87 assert(hb);
88 assert(net);
89 assert(nmt);
90
91 int errc = 0;
92
93 hb->net = net;
94 hb->nmt = nmt;
95
96 hb->recv = can_recv_create();
97 if (__unlikely(!hb->recv)) {
98 errc = get_errc();
99 goto error_create_recv;
100 }
102
103 hb->timer = can_timer_create();
104 if (__unlikely(!hb->timer)) {
105 errc = get_errc();
106 goto error_create_timer;
107 }
109
110 hb->id = 0;
111 hb->st = 0;
112 hb->ms = 0;
114
115 return hb;
116
118error_create_timer:
120error_create_recv:
121 set_errc(errc);
122 return NULL;
123}
124
125void
126__co_nmt_hb_fini(struct __co_nmt_hb *hb)
127{
128 assert(hb);
129
132}
133
136{
137 int errc = 0;
138
139 co_nmt_hb_t *hb = __co_nmt_hb_alloc();
140 if (__unlikely(!hb)) {
141 errc = get_errc();
142 goto error_alloc_hb;
143 }
144
145 if (__unlikely(!__co_nmt_hb_init(hb, net, nmt))) {
146 errc = get_errc();
147 goto error_init_hb;
148 }
149
150 return hb;
151
152error_init_hb:
153 __co_nmt_hb_free(hb);
154error_alloc_hb:
155 set_errc(errc);
156 return NULL;
157}
158
159void
161{
162 if (hb) {
163 __co_nmt_hb_fini(hb);
164 __co_nmt_hb_free(hb);
165 }
166}
167
168void
169co_nmt_hb_set_1016(co_nmt_hb_t *hb, co_unsigned8_t id, co_unsigned16_t ms)
170{
171 assert(hb);
172
173 can_recv_stop(hb->recv);
175
176 hb->id = id;
177 hb->st = 0;
178 hb->ms = ms;
180
181 if (hb->id && hb->id <= CO_NUM_NODES && hb->ms)
182 can_recv_start(hb->recv, hb->net, CO_NMT_EC_CANID(hb->id), 0);
183}
184
185void
186co_nmt_hb_set_st(co_nmt_hb_t *hb, co_unsigned8_t st)
187{
188 assert(hb);
189
190 if (hb->id && hb->id <= CO_NUM_NODES && hb->ms) {
191 hb->st = st;
193 // Reset the CAN timer for the heartbeat consumer.
194 can_timer_timeout(hb->timer, hb->net, hb->ms);
195 }
196}
197
198static int
199co_nmt_hb_recv(const struct can_msg *msg, void *data)
200{
201 assert(msg);
202 co_nmt_hb_t *hb = data;
203 assert(hb);
204 assert(hb->id && hb->id <= CO_NUM_NODES);
205 assert(msg->id == (uint32_t)CO_NMT_EC_CANID(hb->id));
206 assert(hb->ms);
207
208 // Obtain the node status from the CAN frame. Ignore if the toggle bit
209 // is set, since then it is not a heartbeat message.
210 if (__unlikely(msg->len < 1))
211 return 0;
212 co_unsigned8_t st = msg->data[0];
214 return 0;
215
216 // Update the state.
217 co_unsigned8_t old_st = hb->st;
218 co_nmt_hb_set_st(hb, st);
219
220 if (hb->state == CO_NMT_EC_OCCURRED) {
221 diag(DIAG_INFO, 0,
222 "NMT: heartbeat time out resolved for node %d",
223 hb->id);
224 // If a heartbeat timeout event occurred, notify the user that
225 // it has been resolved.
227 co_nmt_hb_ind(hb->nmt, hb->id, hb->state, CO_NMT_EC_TIMEOUT, 0);
228 }
229
230 // Notify the application of the occurrence of a state change.
231 if (st != old_st) {
232 diag(DIAG_INFO, 0,
233 "NMT: heartbeat state change occurred for node %d",
234 hb->id);
237 }
238
239 return 0;
240}
241
242static int
243co_nmt_hb_timer(const struct timespec *tp, void *data)
244{
245 (void)tp;
246 co_nmt_hb_t *hb = data;
247 assert(hb);
248
249 // Notify the application of the occurrence of a heartbeat timeout
250 // event.
251 diag(DIAG_INFO, 0, "NMT: heartbeat time out occurred for node %d",
252 hb->id);
254 co_nmt_hb_ind(hb->nmt, hb->id, hb->state, CO_NMT_EC_TIMEOUT, 0);
255
256 return 0;
257}
This header file is part of the CANopen library; it contains the device description declarations.
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
This header file is part of the utilities library; it contains the diagnostic declarations.
@ DIAG_INFO
An informational message.
Definition: diag.h:45
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
void can_timer_stop(can_timer_t *timer)
Stops a CAN timer and unregisters it with a network interface.
Definition: net.c:468
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition: net.c:382
void can_timer_set_func(can_timer_t *timer, can_timer_func_t *func, void *data)
Sets the callback function invoked when a CAN timer is triggered.
Definition: net.c:428
void can_recv_stop(can_recv_t *recv)
Stops a CAN frame receiver from processing frames and unregisters it with the network interface.
Definition: net.c:613
void can_recv_set_func(can_recv_t *recv, can_recv_func_t *func, void *data)
Sets the callback function used to process CAN frames with a receiver.
Definition: net.c:582
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition: net.c:562
void can_timer_timeout(can_timer_t *timer, can_net_t *net, int timeout)
Starts a CAN timer and registers it with a network interface.
Definition: net.c:484
void can_recv_start(can_recv_t *recv, can_net_t *net, uint_least32_t id, uint_least8_t flags)
Registers a CAN frame receiver with a network interface and starts processing frames.
Definition: net.c:591
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition: net.c:537
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition: net.c:407
void co_nmt_hb_ind(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason, co_unsigned8_t st)
The CANopen NMT heartbeat indication function, invoked when a heartbeat event occurs.
Definition: nmt.c:1968
@ CO_NMT_EC_OCCURRED
An NMT error control event occurred.
Definition: nmt.h:80
@ CO_NMT_EC_RESOLVED
An NMT error control event was resolved.
Definition: nmt.h:82
#define CO_NMT_EC_CANID(id)
The CAN identifier used for both node guarding and heartbeat monitoring.
Definition: nmt.h:76
#define CO_NMT_ST_TOGGLE
The mask to get/set the toggle bit from an NMT state.
Definition: nmt.h:73
@ CO_NMT_EC_STATE
An NMT error control state change event.
Definition: nmt.h:89
@ CO_NMT_EC_TIMEOUT
An NMT error control timeout event.
Definition: nmt.h:87
void co_nmt_hb_destroy(co_nmt_hb_t *hb)
Destroys a CANopen NMT heartbeat consumer service.
Definition: nmt_hb.c:160
void co_nmt_hb_set_1016(co_nmt_hb_t *hb, co_unsigned8_t id, co_unsigned16_t ms)
Processes the value of CANopen object 1016 (Consumer heartbeat time) for the specified heartbeat cons...
Definition: nmt_hb.c:169
static int co_nmt_hb_timer(const struct timespec *tp, void *data)
The CAN timer callback function for a heartbeat consumer.
Definition: nmt_hb.c:243
static int co_nmt_hb_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a heartbeat consumer.
Definition: nmt_hb.c:199
co_nmt_hb_t * co_nmt_hb_create(can_net_t *net, co_nmt_t *nmt)
Creates a new CANopen NMT heartbeat consumer service.
Definition: nmt_hb.c:135
void co_nmt_hb_set_st(co_nmt_hb_t *hb, co_unsigned8_t st)
Sets the expected state of a remote NMT node.
Definition: nmt_hb.c:186
This is the internal header file of the NMT heartbeat consumer declarations.
This is the internal header file of the CANopen library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A CAN network interface.
Definition: net.c:37
A CAN frame receiver.
Definition: net.c:99
A CAN timer.
Definition: net.c:63
A CANopen NMT heartbeat consumer.
Definition: nmt_hb.c:33
can_timer_t * timer
A pointer to the CAN timer.
Definition: nmt_hb.c:41
co_unsigned8_t st
The state of the node (excluding the toggle bit).
Definition: nmt_hb.c:45
can_net_t * net
A pointer to a CAN network interface.
Definition: nmt_hb.c:35
co_unsigned16_t ms
The consumer heartbeat time (in milliseconds).
Definition: nmt_hb.c:47
co_unsigned8_t id
The node-ID.
Definition: nmt_hb.c:43
co_nmt_t * nmt
A pointer to an NMT master/slave service.
Definition: nmt_hb.c:37
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: nmt_hb.c:39
int state
Indicates whether a heartbeat error occurred (CO_NMT_EC_OCCURRED or CO_NMT_EC_RESOLVED).
Definition: nmt_hb.c:52
A CANopen NMT master/slave service.
Definition: nmt.c:104
A CAN or CAN FD format frame.
Definition: msg.h:88
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition: msg.h:103
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition: msg.h:90
uint_least8_t len
The number of bytes in data (or the requested number of bytes in case of a remote frame).
Definition: msg.h:101
A time type with nanosecond resolution.
Definition: time.h:83