24
24
#include <uavcan/node/port/List_0_1.h>
25
25
#include <uavcan/_register/Access_1_0.h>
26
26
#include <uavcan/_register/List_1_0.h>
27
+ #ifdef CAN_CLASSIC
28
+ #include <uavcan/pnp/NodeIDAllocationData_1_0.h>
29
+ #else
27
30
#include <uavcan/pnp/NodeIDAllocationData_2_0.h>
28
-
31
+ #endif /* CAN_CLASSIC */
29
32
// Use /sample/ instead of /unit/ if you need timestamping.
30
33
#include <uavcan/si/unit/pressure/Scalar_1_0.h>
31
34
#include <uavcan/si/unit/temperature/Scalar_1_0.h>
43
46
/// For CAN FD the queue can be smaller.
44
47
#define CAN_TX_QUEUE_CAPACITY 100
45
48
49
+ #ifdef CAN_CLASSIC
50
+ #define CRC64WE_POLY 0x92F0E1EAABEA3693
51
+ #define CRC64WE_INIT 0xFFFFFFFFFFFFFFFF
52
+ #define CRC64WE_XOROUT 0xFFFFFFFFFFFFFFFF
53
+
54
+ static uint64_t crc64we_table [256 ];
55
+
56
+ static void init_crc64we_table ()
57
+ {
58
+ for (uint64_t i = 0 ; i < 256 ; i ++ )
59
+ {
60
+ uint64_t crc = i ;
61
+ for (uint64_t j = 0 ; j < 8 ; j ++ )
62
+ {
63
+ if (crc & 1 )
64
+ crc = (crc >> 1 ) ^ CRC64WE_POLY ;
65
+ else
66
+ crc = crc >> 1 ;
67
+ }
68
+ crc64we_table [i ] = crc ;
69
+ }
70
+ }
71
+
72
+ static uint64_t crc64we (const uint8_t * data , size_t length )
73
+ {
74
+ uint64_t crc = CRC64WE_INIT ;
75
+
76
+ for (size_t i = 0 ; i < length ; i ++ )
77
+ {
78
+ uint8_t byte = data [i ];
79
+ crc = crc64we_table [(crc ^ byte ) & 0xFF ] ^ (crc >> 8 );
80
+ }
81
+
82
+ return crc ^ CRC64WE_XOROUT ;
83
+ }
84
+ #endif /* CAN_CLASSIC */
85
+
46
86
/// We keep the state of the application here. Feel free to use static variables instead if desired.
47
87
typedef struct State
48
88
{
@@ -255,20 +295,35 @@ static void handle1HzLoop(State* const state, const CanardMicrosecond monotonic_
255
295
// Note that a high-integrity/safety-certified application is unlikely to be able to rely on this feature.
256
296
if (rand () > RAND_MAX / 2 ) // NOLINT
257
297
{
258
- // Note that this will only work over CAN FD. If you need to run PnP over Classic CAN, use message v1.0.
298
+ #ifdef CAN_CLASSIC
299
+ uavcan_pnp_NodeIDAllocationData_1_0 msg = {0 };
300
+ uint8_t uid [uavcan_node_GetInfo_Response_1_0_unique_id_ARRAY_CAPACITY_ ] = {0 };
301
+ getUniqueID (uid );
302
+ init_crc64we_table ();
303
+ uint64_t uid_hash = crc64we (uid , sizeof uid );
304
+ memcpy (& msg .unique_id_hash , & uid_hash , 5 );
305
+ uint8_t serialized [uavcan_pnp_NodeIDAllocationData_1_0_SERIALIZATION_BUFFER_SIZE_BYTES_ ] = {0 };
306
+ size_t serialized_size = sizeof (serialized );
307
+ const int8_t err = uavcan_pnp_NodeIDAllocationData_1_0_serialize_ (& msg , & serialized [0 ], & serialized_size );
308
+ #else
259
309
uavcan_pnp_NodeIDAllocationData_2_0 msg = {0 };
260
310
msg .node_id .value = UINT16_MAX ;
261
311
getUniqueID (msg .unique_id );
262
312
uint8_t serialized [uavcan_pnp_NodeIDAllocationData_2_0_SERIALIZATION_BUFFER_SIZE_BYTES_ ] = {0 };
263
313
size_t serialized_size = sizeof (serialized );
264
- const int8_t err = uavcan_pnp_NodeIDAllocationData_2_0_serialize_ (& msg , & serialized [0 ], & serialized_size );
314
+ const int8_t err = uavcan_pnp_NodeIDAllocationData_2_0_serialize_ (& msg , & serialized [0 ], & serialized_size );
315
+ #endif /* CAN_CLASSIC */
265
316
assert (err >= 0 );
266
317
if (err >= 0 )
267
318
{
268
319
const CanardTransferMetadata meta = {
269
320
.priority = CanardPrioritySlow ,
270
321
.transfer_kind = CanardTransferKindMessage ,
322
+ #ifdef CAN_CLASSIC
323
+ .port_id = uavcan_pnp_NodeIDAllocationData_1_0_FIXED_PORT_ID_ ,
324
+ #else
271
325
.port_id = uavcan_pnp_NodeIDAllocationData_2_0_FIXED_PORT_ID_ ,
326
+ #endif
272
327
.remote_node_id = CANARD_NODE_ID_UNSET ,
273
328
.transfer_id = (CanardTransferID ) (state -> next_transfer_id .uavcan_pnp_allocation ++ ),
274
329
};
@@ -381,7 +436,33 @@ static void handle01HzLoop(State* const state, const CanardMicrosecond monotonic
381
436
}
382
437
}
383
438
}
384
-
439
+ #ifdef CAN_CLASSIC
440
+ static void processMessagePlugAndPlayNodeIDAllocation (State * const state ,
441
+ const uavcan_pnp_NodeIDAllocationData_1_0 * const msg )
442
+ {
443
+ uint8_t uid [uavcan_node_GetInfo_Response_1_0_unique_id_ARRAY_CAPACITY_ ] = {0 };
444
+ getUniqueID (uid );
445
+ init_crc64we_table ();
446
+ uint64_t uid_hash = crc64we (uid , sizeof uid );
447
+ if (msg -> allocated_node_id .count > 0 && (msg -> allocated_node_id .elements [0 ].value <= CANARD_NODE_ID_MAX ) &&
448
+ (memcmp (& uid_hash , & msg -> unique_id_hash , 5 /*sizeof(uid)*/ ) == 0 ))
449
+ {
450
+ printf ("Got PnP node-ID allocation: %d\n" , msg -> allocated_node_id .elements [0 ].value );
451
+ state -> canard .node_id = (CanardNodeID ) msg -> allocated_node_id .elements [0 ].value ;
452
+ // Store the value into the non-volatile storage.
453
+ uavcan_register_Value_1_0 reg = {0 };
454
+ uavcan_register_Value_1_0_select_natural16_ (& reg );
455
+ reg .natural16 .value .elements [0 ] = msg -> allocated_node_id .elements [0 ].value ;
456
+ reg .natural16 .value .count = 1 ;
457
+ registerWrite ("uavcan.node.id" , & reg );
458
+ // We no longer need the subscriber, drop it to free up the resources (both memory and CPU time).
459
+ (void ) canardRxUnsubscribe (& state -> canard ,
460
+ CanardTransferKindMessage ,
461
+ uavcan_pnp_NodeIDAllocationData_1_0_FIXED_PORT_ID_ );
462
+ }
463
+ // Otherwise, ignore it: either it is a request from another node or it is a response to another node.
464
+ }
465
+ #else
385
466
static void processMessagePlugAndPlayNodeIDAllocation (State * const state ,
386
467
const uavcan_pnp_NodeIDAllocationData_2_0 * const msg )
387
468
{
@@ -404,6 +485,7 @@ static void processMessagePlugAndPlayNodeIDAllocation(State* const
404
485
}
405
486
// Otherwise, ignore it: either it is a request from another node or it is a response to another node.
406
487
}
488
+ #endif /* CAN_CLASSIC */
407
489
408
490
static uavcan_node_ExecuteCommand_Response_1_1 processRequestExecuteCommand (
409
491
const uavcan_node_ExecuteCommand_Request_1_1 * req )
@@ -525,10 +607,17 @@ static void processReceivedTransfer(State* const state, const CanardRxTransfer*
525
607
if (transfer -> metadata .transfer_kind == CanardTransferKindMessage )
526
608
{
527
609
size_t size = transfer -> payload_size ;
610
+ #ifdef CAN_CLASSIC
611
+ if (transfer -> metadata .port_id == uavcan_pnp_NodeIDAllocationData_1_0_FIXED_PORT_ID_ )
612
+ {
613
+ uavcan_pnp_NodeIDAllocationData_1_0 msg = {0 };
614
+ if (uavcan_pnp_NodeIDAllocationData_1_0_deserialize_ (& msg , transfer -> payload , & size ) >= 0 )
615
+ #else
528
616
if (transfer -> metadata .port_id == uavcan_pnp_NodeIDAllocationData_2_0_FIXED_PORT_ID_ )
529
617
{
530
618
uavcan_pnp_NodeIDAllocationData_2_0 msg = {0 };
531
619
if (uavcan_pnp_NodeIDAllocationData_2_0_deserialize_ (& msg , transfer -> payload , & size ) >= 0 )
620
+ #endif /* CAN_CLASSIC */
532
621
{
533
622
processMessagePlugAndPlayNodeIDAllocation (state , & msg );
534
623
}
@@ -698,18 +787,24 @@ int main(const int argc, char* const argv[])
698
787
// Configure the transport by reading the appropriate standard registers.
699
788
uavcan_register_Value_1_0_select_natural16_ (& val );
700
789
val .natural16 .value .count = 1 ;
790
+ #ifdef CAN_CLASSIC
791
+ val .natural16 .value .elements [0 ] = CANARD_MTU_CAN_CLASSIC ;
792
+ #else
701
793
val .natural16 .value .elements [0 ] = CANARD_MTU_CAN_FD ;
794
+ #endif
702
795
registerRead ("uavcan.can.mtu" , & val );
703
796
assert (uavcan_register_Value_1_0_is_natural16_ (& val ) && (val .natural16 .value .count == 1 ));
704
797
// We also need the bitrate configuration register. In this demo we can't really use it but an embedded application
705
798
// should define "uavcan.can.bitrate" of type natural32[2]; the second value is 0/ignored if CAN FD not supported.
799
+ const char iface_name [] = "vcan0" ;
706
800
const int sock [CAN_REDUNDANCY_FACTOR ] = {
707
- socketcanOpen ("vcan0" , val .natural16 .value .elements [0 ] > CANARD_MTU_CAN_CLASSIC ) //
801
+ socketcanOpen (iface_name , val .natural16 .value .elements [0 ] > CANARD_MTU_CAN_CLASSIC ) //
708
802
};
709
803
for (uint8_t ifidx = 0 ; ifidx < CAN_REDUNDANCY_FACTOR ; ifidx ++ )
710
804
{
711
805
if (sock [ifidx ] < 0 )
712
806
{
807
+ printf ("Unable to open can interface '%s'" , iface_name );
713
808
return - sock [ifidx ];
714
809
}
715
810
state .canard_tx_queues [ifidx ] = canardTxInit (CAN_TX_QUEUE_CAPACITY , val .natural16 .value .elements [0 ]);
@@ -734,8 +829,13 @@ int main(const int argc, char* const argv[])
734
829
const int8_t res = //
735
830
canardRxSubscribe (& state .canard ,
736
831
CanardTransferKindMessage ,
832
+ #ifdef CAN_CLASSIC
833
+ uavcan_pnp_NodeIDAllocationData_1_0_FIXED_PORT_ID_ ,
834
+ uavcan_pnp_NodeIDAllocationData_1_0_EXTENT_BYTES_ ,
835
+ #else
737
836
uavcan_pnp_NodeIDAllocationData_2_0_FIXED_PORT_ID_ ,
738
837
uavcan_pnp_NodeIDAllocationData_2_0_EXTENT_BYTES_ ,
838
+ #endif
739
839
CANARD_DEFAULT_TRANSFER_ID_TIMEOUT_USEC ,
740
840
& rx );
741
841
if (res < 0 )
0 commit comments