forked from OpenCyphal/libcanard
-
Notifications
You must be signed in to change notification settings - Fork 3
/
canard.h
497 lines (441 loc) · 23.2 KB
/
canard.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
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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
/*
* Copyright (c) 2016-2017 UAVCAN Team
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Contributors: https://github.com/UAVCAN/libcanard/contributors
*
* Documentation: http://uavcan.org/Implementations/Libcanard
*/
#ifndef CANARD_H
#define CANARD_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <assert.h>
#ifdef __cplusplus
extern "C" {
#endif
/// Libcanard version. API will be backwards compatible within the same major version.
#define CANARD_VERSION_MAJOR 0
#define CANARD_VERSION_MINOR 1
/// By default this macro resolves to the standard assert(). The user can redefine this if necessary.
#ifndef CANARD_ASSERT
# define CANARD_ASSERT(x) assert(x)
#endif
/// Error code definitions; inverse of these values may be returned from API calls.
#define CANARD_OK 0
// Value 1 is omitted intentionally, since -1 is often used in 3rd party code
#define CANARD_ERROR_INVALID_ARGUMENT 2
#define CANARD_ERROR_OUT_OF_MEMORY 3
#define CANARD_ERROR_NODE_ID_NOT_SET 4
#define CANARD_ERROR_INTERNAL 9
/// The size of a memory block in bytes.
#define CANARD_MEM_BLOCK_SIZE 32
/// This will be changed when the support for CAN FD is added
#define CANARD_CAN_FRAME_MAX_DATA_LEN 8
/// Node ID values. Refer to the specification for more info.
#define CANARD_BROADCAST_NODE_ID 0
#define CANARD_MIN_NODE_ID 1
#define CANARD_MAX_NODE_ID 127
/// Refer to the type CanardRxTransfer
#define CANARD_MULTIFRAME_RX_PAYLOAD_HEAD_SIZE (CANARD_MEM_BLOCK_SIZE - offsetof(CanardRxState, buffer_head))
/// Refer to the type CanardBufferBlock
#define CANARD_BUFFER_BLOCK_DATA_SIZE (CANARD_MEM_BLOCK_SIZE - offsetof(CanardBufferBlock, data))
/// Refer to canardCleanupStaleTransfers() for details.
#define CANARD_RECOMMENDED_STALE_TRANSFER_CLEANUP_INTERVAL_USEC 1000000U
/// Transfer priority definitions
#define CANARD_TRANSFER_PRIORITY_HIGHEST 0
#define CANARD_TRANSFER_PRIORITY_HIGH 8
#define CANARD_TRANSFER_PRIORITY_MEDIUM 16
#define CANARD_TRANSFER_PRIORITY_LOW 24
#define CANARD_TRANSFER_PRIORITY_LOWEST 31
/// Related to CanardCANFrame
#define CANARD_CAN_EXT_ID_MASK 0x1FFFFFFFU
#define CANARD_CAN_STD_ID_MASK 0x000007FFU
#define CANARD_CAN_FRAME_EFF (1UL << 31) ///< Extended frame format
#define CANARD_CAN_FRAME_RTR (1UL << 30) ///< Remote transmission (not used by UAVCAN)
#define CANARD_CAN_FRAME_ERR (1UL << 29) ///< Error frame (not used by UAVCAN)
/**
* This data type holds a standard CAN 2.0B data frame with 29-bit ID.
*/
typedef struct
{
/**
* Refer to the following definitions:
* - CANARD_CAN_FRAME_EFF
* - CANARD_CAN_FRAME_RTR
* - CANARD_CAN_FRAME_ERR
*/
uint32_t id;
uint8_t data[CANARD_CAN_FRAME_MAX_DATA_LEN];
uint8_t data_len;
} CanardCANFrame;
/**
* Transfer types are defined by the UAVCAN specification.
*/
typedef enum
{
CanardTransferTypeResponse = 0,
CanardTransferTypeRequest = 1,
CanardTransferTypeBroadcast = 2
} CanardTransferType;
/**
* Types of service transfers. These are not applicable to message transfers.
*/
typedef enum
{
CanardResponse,
CanardRequest
} CanardRequestResponse;
/*
* Forward declarations.
*/
typedef struct CanardInstance CanardInstance;
typedef struct CanardRxTransfer CanardRxTransfer;
typedef struct CanardRxState CanardRxState;
typedef struct CanardTxQueueItem CanardTxQueueItem;
/**
* The application must implement this function and supply a pointer to it to the library during initialization.
* The library calls this function to determine whether the transfer should be received.
*
* If the application returns true, the value pointed to by 'out_data_type_signature' must be initialized with the
* correct data type signature, otherwise transfer reception will fail with CRC mismatch error. Please refer to the
* specification for more details about data type signatures. Signature for any data type can be obtained in many
* ways; for example, using the command line tool distributed with Libcanard (see the repository).
*/
typedef bool (* CanardShouldAcceptTransfer)(const CanardInstance* ins, ///< Library instance
uint64_t* out_data_type_signature, ///< Must be set by the application!
uint16_t data_type_id, ///< Refer to the specification
CanardTransferType transfer_type, ///< Refer to CanardTransferType
uint8_t source_node_id); ///< Source node ID or Broadcast (0)
/**
* This function will be invoked by the library every time a transfer is successfully received.
* If the application needs to send another transfer from this callback, it is highly recommended
* to call canardReleaseRxTransferPayload() first, so that the memory that was used for the block
* buffer can be released and re-used by the TX queue.
*/
typedef void (* CanardOnTransferReception)(CanardInstance* ins, ///< Library instance
CanardRxTransfer* transfer); ///< Ptr to temporary transfer object
/**
* INTERNAL DEFINITION, DO NOT USE DIRECTLY.
* A memory block used in the memory block allocator.
*/
typedef union CanardPoolAllocatorBlock_u
{
char bytes[CANARD_MEM_BLOCK_SIZE];
union CanardPoolAllocatorBlock_u* next;
} CanardPoolAllocatorBlock;
/**
* This structure provides usage statistics of the memory pool allocator.
* This data helps to evaluate whether the allocated memory is sufficient for the application.
*/
typedef struct
{
uint16_t capacity_blocks; ///< Pool capacity in number of blocks
uint16_t current_usage_blocks; ///< Number of blocks that are currently allocated by the library
uint16_t peak_usage_blocks; ///< Maximum number of blocks used since initialization
} CanardPoolAllocatorStatistics;
/**
* INTERNAL DEFINITION, DO NOT USE DIRECTLY.
*/
typedef struct
{
CanardPoolAllocatorBlock* free_list;
CanardPoolAllocatorStatistics statistics;
} CanardPoolAllocator;
/**
* INTERNAL DEFINITION, DO NOT USE DIRECTLY.
* Buffer block for received data.
*/
typedef struct CanardBufferBlock
{
struct CanardBufferBlock* next;
uint8_t data[];
} CanardBufferBlock;
/**
* INTERNAL DEFINITION, DO NOT USE DIRECTLY.
*/
struct CanardRxState
{
struct CanardRxState* next;
CanardBufferBlock* buffer_blocks;
uint64_t timestamp_usec;
const uint32_t dtid_tt_snid_dnid;
uint16_t payload_crc;
// We're using plain 'unsigned' here, because C99 doesn't permit explicit field type specification
unsigned calculated_crc : 16;
unsigned payload_len : 10;
unsigned transfer_id : 5;
unsigned next_toggle : 1; // 16+10+5+1 = 32, aligned.
uint8_t buffer_head[];
};
/**
* This is the core structure that keeps all of the states and allocated resources of the library instance.
* The application should never access any of the fields directly! Instead, API functions should be used.
*/
struct CanardInstance
{
uint8_t node_id; ///< Local node ID; may be zero if the node is anonymous
CanardShouldAcceptTransfer should_accept; ///< Function to decide whether the application wants this transfer
CanardOnTransferReception on_reception; ///< Function the library calls after RX transfer is complete
CanardPoolAllocator allocator; ///< Pool allocator
CanardRxState* rx_states; ///< RX transfer states
CanardTxQueueItem* tx_queue; ///< TX frames awaiting transmission
void* user_reference; ///< User pointer that can link this instance with other objects
};
/**
* This structure represents a received transfer for the application.
* An instance of it is passed to the application via callback when the library receives a new transfer.
* Pointers to the structure and all its fields are invalidated after the callback returns.
*/
struct CanardRxTransfer
{
/**
* Timestamp at which the first frame of this transfer was received.
*/
uint64_t timestamp_usec;
/**
* Payload is scattered across three storages:
* - Head points to CanardRxState.buffer_head (length of which is up to CANARD_PAYLOAD_HEAD_SIZE), or to the
* payload field (possibly with offset) of the last received CAN frame.
*
* - Middle is located in the linked list of dynamic blocks (only for multi-frame transfers).
*
* - Tail points to the payload field (possibly with offset) of the last received CAN frame
* (only for multi-frame transfers).
*
* The tail offset depends on how much data of the last frame was accommodated in the last allocated block.
*
* For single-frame transfers, middle and tail will be NULL, and the head will point at first byte
* of the payload of the CAN frame.
*
* In simple cases it should be possible to get data directly from the head and/or tail pointers.
* Otherwise it is advised to use canardDecodeScalar().
*/
const uint8_t* payload_head; ///< Always valid, i.e. not NULL.
///< For multi frame transfers, the maximum size is defined in the constant
///< CANARD_MULTIFRAME_RX_PAYLOAD_HEAD_SIZE.
///< For single-frame transfers, the size is defined in the
///< field payload_len.
CanardBufferBlock* payload_middle; ///< May be NULL if the buffer was not needed. Always NULL for single-frame
///< transfers.
const uint8_t* payload_tail; ///< Last bytes of multi-frame transfers. Always NULL for single-frame
///< transfers.
uint16_t payload_len; ///< Effective length of the payload in bytes.
/**
* These fields identify the transfer for the application.
*/
uint16_t data_type_id; ///< 0 to 255 for services, 0 to 65535 for messages
uint8_t transfer_type; ///< See CanardTransferType
uint8_t transfer_id; ///< 0 to 31
uint8_t priority; ///< 0 to 31
uint8_t source_node_id; ///< 1 to 127, or 0 if the source is anonymous
};
/**
* Initializes a library instance.
* Local node ID will be set to zero, i.e. the node will be anonymous.
*
* Typically, size of the memory pool should not be less than 1K, although it depends on the application. The
* recommended way to detect the required pool size is to measure the peak pool usage after a stress-test. Refer to
* the function canardGetPoolAllocatorStatistics().
*/
void canardInit(CanardInstance* out_ins, ///< Uninitialized library instance
void* mem_arena, ///< Raw memory chunk used for dynamic allocation
size_t mem_arena_size, ///< Size of the above, in bytes
CanardOnTransferReception on_reception, ///< Callback, see CanardOnTransferReception
CanardShouldAcceptTransfer should_accept, ///< Callback, see CanardShouldAcceptTransfer
void* user_reference); ///< Optional pointer for user's convenience, can be NULL
/**
* Returns the value of the user pointer.
* The user pointer is configured once during initialization.
* It can be used to store references to any user-specific data, or to link the instance object with C++ objects.
*/
void* canardGetUserReference(CanardInstance* ins);
/**
* Assigns a new node ID value to the current node.
* Node ID can be assigned only once.
*/
void canardSetLocalNodeID(CanardInstance* ins,
uint8_t self_node_id);
/**
* Returns node ID of the local node.
* Returns zero (broadcast) if the node ID is not set, i.e. if the local node is anonymous.
*/
uint8_t canardGetLocalNodeID(const CanardInstance* ins);
/**
* Sends a broadcast transfer.
* If the node is in passive mode, only single frame transfers will be allowed (they will be transmitted as anonymous).
*
* For anonymous transfers, maximum data type ID is limited to 3 (see specification for details).
*
* Please refer to the specification for more details about data type signatures. Signature for any data type can be
* obtained in many ways; for example, using the command line tool distributed with Libcanard (see the repository).
*
* Pointer to the Transfer ID should point to a persistent variable (e.g. static or heap allocated, not on the stack);
* it will be updated by the library after every transmission. The Transfer ID value cannot be shared between
* transfers that have different descriptors! More on this in the transport layer specification.
*/
int canardBroadcast(CanardInstance* ins, ///< Library instance
uint64_t data_type_signature, ///< See above
uint16_t data_type_id, ///< Refer to the specification
uint8_t* inout_transfer_id, ///< Pointer to a persistent variable containing the transfer ID
uint8_t priority, ///< Refer to definitions CANARD_TRANSFER_PRIORITY_*
const void* payload, ///< Transfer payload
uint16_t payload_len); ///< Length of the above, in bytes
/**
* Sends a request or a response transfer.
* Fails if the node is in passive mode.
*
* Please refer to the specification for more details about data type signatures. Signature for any data type can be
* obtained in many ways; for example, using the command line tool distributed with Libcanard (see the repository).
*
* For Request transfers, the pointer to the Transfer ID should point to a persistent variable (e.g. static or heap
* allocated, not on the stack); it will be updated by the library after every request. The Transfer ID value
* cannot be shared between requests that have different descriptors! More on this in the transport layer
* specification.
*
* For Response transfers, the pointer to the Transfer ID will be treated as const (i.e. read-only), and normally it
* should point to the transfer_id field of the structure CanardRxTransfer.
*/
int canardRequestOrRespond(CanardInstance* ins, ///< Library instance
uint8_t destination_node_id, ///< Node ID of the server/client
uint64_t data_type_signature, ///< See above
uint8_t data_type_id, ///< Refer to the specification
uint8_t* inout_transfer_id, ///< Pointer to a persistent variable with the transfer ID
uint8_t priority, ///< Refer to definitions CANARD_TRANSFER_PRIORITY_*
CanardRequestResponse kind, ///< Refer to CanardRequestResponse
const void* payload, ///< Transfer payload
uint16_t payload_len); ///< Length of the above, in bytes
/**
* Returns a pointer to the top priority frame in the TX queue.
* Returns NULL if the TX queue is empty.
* The application will call this function after canardBroadcast() or canardRequestOrRespond() to transmit generated
* frames over the CAN bus.
*/
const CanardCANFrame* canardPeekTxQueue(const CanardInstance* ins);
/**
* Removes the top priority frame from the TX queue.
* The application will call this function after canardPeekTxQueue() once the obtained frame has been processed.
* Calling canardBroadcast() or canardRequestOrRespond() between canardPeekTxQueue() and canardPopTxQueue()
* is NOT allowed, because it may change the frame at the top of the TX queue.
*/
void canardPopTxQueue(CanardInstance* ins);
/**
* Processes a received CAN frame with a timestamp.
* The application will call this function when it receives a new frame from the CAN bus.
*/
void canardHandleRxFrame(CanardInstance* ins,
const CanardCANFrame* frame,
uint64_t timestamp_usec);
/**
* Traverses the list of transfers and removes those that were last updated more than timeout_usec microseconds ago.
* This function must be invoked by the application periodically, about once a second.
* Also refer to the constant CANARD_RECOMMENDED_STALE_TRANSFER_CLEANUP_INTERVAL_USEC.
*/
void canardCleanupStaleTransfers(CanardInstance* ins,
uint64_t current_time_usec);
/**
* This function can be used to extract values from received UAVCAN transfers. It decodes a scalar value -
* boolean, integer, character, or floating point - from the specified bit position in the RX transfer buffer.
* Simple single-frame transfers can also be parsed manually.
*
* Returns the number of bits successfully decoded, which may be less than requested if operation ran out of
* buffer boundaries, or negated error code, such as invalid argument.
*
* Caveat: This function works correctly only on platforms that use two's complement signed integer representation.
* I am not aware of any modern microarchitecture that uses anything else than two's complement, so it should
* not affect portability in any way.
*
* The type of value pointed to by 'out_value' is defined as follows:
*
* | bit_length | value_is_signed | out_value points to |
* |------------|-----------------|------------------------------------------|
* | 1 | false | bool (may be incompatible with uint8_t!) |
* | 1 | true | N/A |
* | [2, 8] | false | uint8_t, or char |
* | [2, 8] | true | int8_t, or char |
* | [9, 16] | false | uint16_t |
* | [9, 16] | true | int16_t |
* | [17, 32] | false | uint32_t |
* | [17, 32] | true | int32_t, or 32-bit float |
* | [33, 64] | false | uint64_t |
* | [33, 64] | true | int64_t, or 64-bit float |
*/
int canardDecodeScalar(const CanardRxTransfer* transfer, ///< The RX transfer where the data will be copied from
uint32_t bit_offset, ///< Offset, in bits, from the beginning of the transfer
uint8_t bit_length, ///< Length of the value, in bits; see the table
bool value_is_signed, ///< True if the value can be negative; see the table
void* out_value); ///< Pointer to the output storage; see the table
/**
* This function can be used to encode values for later transmission in a UAVCAN transfer. It encodes a scalar value -
* boolean, integer, character, or floating point - and puts it to the specified bit position in the specified
* contiguous buffer.
* Simple single-frame transfers can also be encoded manually.
*
* Caveat: This function works correctly only on platforms that use two's complement signed integer representation.
* I am not aware of any modern microarchitecture that uses anything else than two's complement, so it should
* not affect portability in any way.
*
* The type of value pointed to by 'value' is defined as follows:
*
* | bit_length | value points to |
* |------------|------------------------------------------|
* | 1 | bool (may be incompatible with uint8_t!) |
* | [2, 8] | uint8_t, int8_t, or char |
* | [9, 16] | uint16_t, int16_t |
* | [17, 32] | uint32_t, int32_t, or 32-bit float |
* | [33, 64] | uint64_t, int64_t, or 64-bit float |
*/
void canardEncodeScalar(void* destination, ///< Destination buffer where the result will be stored
uint32_t bit_offset, ///< Offset, in bits, from the beginning of the destination buffer
uint8_t bit_length, ///< Length of the value, in bits; see the table
const void* value); ///< Pointer to the value; see the table
/**
* This function can be invoked by the application to release pool blocks that are used
* to store the payload of the transfer.
*
* If the application needs to send new transfers from the transfer reception callback, this function should be
* invoked right before calling canardBroadcast() or canardRequestOrRespond(). Not releasing the buffers before
* transmission may cause higher peak usage of the memory pool.
*
* If the application didn't call this function before returning from the callback, the library will do that,
* so it is guaranteed that the memory will not leak.
*/
void canardReleaseRxTransferPayload(CanardInstance* ins,
CanardRxTransfer* transfer);
/**
* Returns a copy of the pool allocator usage statistics.
* Refer to the type CanardPoolAllocatorStatistics.
* Use this function to determine worst case memory needs of your application.
*/
CanardPoolAllocatorStatistics canardGetPoolAllocatorStatistics(CanardInstance* ins);
/**
* Float16 marshaling helpers.
* These functions convert between the native float and 16-bit float.
* It is assumed that the native float is IEEE 754 single precision float, otherwise results will be unpredictable.
* Vast majority of modern computers and microcontrollers use IEEE 754, so this limitation should not affect
* portability.
*/
uint16_t canardConvertNativeFloatToFloat16(float value);
float canardConvertFloat16ToNativeFloat(uint16_t value);
#ifdef __cplusplus
}
#endif
#endif