2424#include <uavcan/node/port/List_0_1.h>
2525#include <uavcan/_register/Access_1_0.h>
2626#include <uavcan/_register/List_1_0.h>
27+ #ifdef CAN_CLASSIC
28+ #include <uavcan/pnp/NodeIDAllocationData_1_0.h>
29+ #else
2730#include <uavcan/pnp/NodeIDAllocationData_2_0.h>
28-
31+ #endif /* CAN_CLASSIC */
2932// Use /sample/ instead of /unit/ if you need timestamping.
3033#include <uavcan/si/unit/pressure/Scalar_1_0.h>
3134#include <uavcan/si/unit/temperature/Scalar_1_0.h>
4346/// For CAN FD the queue can be smaller.
4447#define CAN_TX_QUEUE_CAPACITY 100
4548
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+
4686/// We keep the state of the application here. Feel free to use static variables instead if desired.
4787typedef struct State
4888{
@@ -255,20 +295,35 @@ static void handle1HzLoop(State* const state, const CanardMicrosecond monotonic_
255295 // Note that a high-integrity/safety-certified application is unlikely to be able to rely on this feature.
256296 if (rand () > RAND_MAX / 2 ) // NOLINT
257297 {
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
259309 uavcan_pnp_NodeIDAllocationData_2_0 msg = {0 };
260310 msg .node_id .value = UINT16_MAX ;
261311 getUniqueID (msg .unique_id );
262312 uint8_t serialized [uavcan_pnp_NodeIDAllocationData_2_0_SERIALIZATION_BUFFER_SIZE_BYTES_ ] = {0 };
263313 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 */
265316 assert (err >= 0 );
266317 if (err >= 0 )
267318 {
268319 const CanardTransferMetadata meta = {
269320 .priority = CanardPrioritySlow ,
270321 .transfer_kind = CanardTransferKindMessage ,
322+ #ifdef CAN_CLASSIC
323+ .port_id = uavcan_pnp_NodeIDAllocationData_1_0_FIXED_PORT_ID_ ,
324+ #else
271325 .port_id = uavcan_pnp_NodeIDAllocationData_2_0_FIXED_PORT_ID_ ,
326+ #endif
272327 .remote_node_id = CANARD_NODE_ID_UNSET ,
273328 .transfer_id = (CanardTransferID ) (state -> next_transfer_id .uavcan_pnp_allocation ++ ),
274329 };
@@ -381,7 +436,33 @@ static void handle01HzLoop(State* const state, const CanardMicrosecond monotonic
381436 }
382437 }
383438}
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
385466static void processMessagePlugAndPlayNodeIDAllocation (State * const state ,
386467 const uavcan_pnp_NodeIDAllocationData_2_0 * const msg )
387468{
@@ -404,6 +485,7 @@ static void processMessagePlugAndPlayNodeIDAllocation(State* const
404485 }
405486 // Otherwise, ignore it: either it is a request from another node or it is a response to another node.
406487}
488+ #endif /* CAN_CLASSIC */
407489
408490static uavcan_node_ExecuteCommand_Response_1_1 processRequestExecuteCommand (
409491 const uavcan_node_ExecuteCommand_Request_1_1 * req )
@@ -525,10 +607,17 @@ static void processReceivedTransfer(State* const state, const CanardRxTransfer*
525607 if (transfer -> metadata .transfer_kind == CanardTransferKindMessage )
526608 {
527609 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
528616 if (transfer -> metadata .port_id == uavcan_pnp_NodeIDAllocationData_2_0_FIXED_PORT_ID_ )
529617 {
530618 uavcan_pnp_NodeIDAllocationData_2_0 msg = {0 };
531619 if (uavcan_pnp_NodeIDAllocationData_2_0_deserialize_ (& msg , transfer -> payload , & size ) >= 0 )
620+ #endif /* CAN_CLASSIC */
532621 {
533622 processMessagePlugAndPlayNodeIDAllocation (state , & msg );
534623 }
@@ -703,13 +792,15 @@ int main(const int argc, char* const argv[])
703792 assert (uavcan_register_Value_1_0_is_natural16_ (& val ) && (val .natural16 .value .count == 1 ));
704793 // We also need the bitrate configuration register. In this demo we can't really use it but an embedded application
705794 // should define "uavcan.can.bitrate" of type natural32[2]; the second value is 0/ignored if CAN FD not supported.
795+ const char iface_name [] = "vcan0" ;
706796 const int sock [CAN_REDUNDANCY_FACTOR ] = {
707- socketcanOpen ("vcan0" , val .natural16 .value .elements [0 ] > CANARD_MTU_CAN_CLASSIC ) //
797+ socketcanOpen (iface_name , val .natural16 .value .elements [0 ] > CANARD_MTU_CAN_CLASSIC ) //
708798 };
709799 for (uint8_t ifidx = 0 ; ifidx < CAN_REDUNDANCY_FACTOR ; ifidx ++ )
710800 {
711801 if (sock [ifidx ] < 0 )
712802 {
803+ printf ("Unable to open can interface '%s'" , iface_name );
713804 return - sock [ifidx ];
714805 }
715806 state .canard_tx_queues [ifidx ] = canardTxInit (CAN_TX_QUEUE_CAPACITY , val .natural16 .value .elements [0 ]);
@@ -734,8 +825,13 @@ int main(const int argc, char* const argv[])
734825 const int8_t res = //
735826 canardRxSubscribe (& state .canard ,
736827 CanardTransferKindMessage ,
828+ #ifdef CAN_CLASSIC
829+ uavcan_pnp_NodeIDAllocationData_1_0_FIXED_PORT_ID_ ,
830+ uavcan_pnp_NodeIDAllocationData_1_0_EXTENT_BYTES_ ,
831+ #else
737832 uavcan_pnp_NodeIDAllocationData_2_0_FIXED_PORT_ID_ ,
738833 uavcan_pnp_NodeIDAllocationData_2_0_EXTENT_BYTES_ ,
834+ #endif
739835 CANARD_DEFAULT_TRANSFER_ID_TIMEOUT_USEC ,
740836 & rx );
741837 if (res < 0 )
0 commit comments