Lely core libraries 1.9.2
nmt_hb.c
Go to the documentation of this file.
1
23
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
struct __co_nmt co_nmt_t
An opaque CANopen NMT master/slave service type.
Definition co.h:145
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
struct __can_net can_net_t
An opaque CAN network interface type.
Definition net.h:31
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
struct __can_timer can_timer_t
An opaque CAN timer type.
Definition net.h:37
struct __can_recv can_recv_t
An opaque CAN frame receiver type.
Definition net.h:43
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
@ 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
#define CO_NMT_ST_TOGGLE
The mask to get/set the toggle bit from an NMT state.
Definition nmt.h:73
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.
struct __co_nmt_hb co_nmt_hb_t
An opaque CANopen NMT heartbeat consumer type.
Definition nmt_hb.h:32
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 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 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