Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
titleLibcanard initialization
static CanardInstance g_canard;             // The library instance
static uint8_t g_canard_memory_pool[1024]; 	// Arena for memory allocation, used by the library

static void swInit(void)
{
    CanardSTM32CANTimings timings;
    int result = canardSTM32ComputeCANTimings(RCC_Clocks.PCLK1_Frequency, 1000000, &timings);
    if (result)
    {
        __ASM volatile("BKPT #01"); 
    }
    result = canardSTM32Init(&timings, CanardSTM32IfaceModeNormal);
    if (result)
    {
        __ASM volatile("BKPT #01"); 
    }

    canardInit(&g_canard,                         // Uninitialized library instance
               g_canard_memory_pool,              // Raw memory chunk used for dynamic allocation
               sizeof(g_canard_memory_pool),      // Size of the above, in bytes
               onTransferReceived,                // Callback, see CanardOnTransferReception
               shouldAcceptTransfer,              // Callback, see CanardShouldAcceptTransfer
               NULL); 

    canardSetLocalNodeID(&g_canard, 100);
}

canardSTM32Init and canardSTM32ComputeCANTimings are stm32-specific driver functions shipped with libcanard intended to simplify the CAN peripheral setup procedure.

...

Code Block
titleshouldAcceptTransfer
static bool shouldAcceptTransfer(const CanardInstance* ins,
                          uint64_t* out_data_type_signature,
                          uint16_t data_type_id,
                          CanardTransferType transfer_type,
                          uint8_t source_node_id)
{
    if ((transfer_type == CanardTransferTypeRequest) &&
        (data_type_id == UAVCAN_GET_NODE_INFO_DATA_TYPE_ID))
    {
        *out_data_type_signature = UAVCAN_GET_NODE_INFO_DATA_TYPE_SIGNATURE;
        return true;
    }
  
    return false;
}

...

Code Block
titleonTransferReceived
static void onTransferReceived(CanardInstance* ins, CanardRxTransfer* transfer)
{
    if ((transfer->transfer_type == CanardTransferTypeRequest) &&
    (transfer->data_type_id == UAVCAN_GET_NODE_INFO_DATA_TYPE_ID))
    {
        canardGetNodeInfoHandle(transfer);
    } 
}

...

Code Block
titlecanard_service
#define CANARD_SPIN_PERIOD    1000

static void spinCanard(void)
{
    static uint32_t spin_time = 0;
    if (getUptime() < spin_time + CANARD_SPIN_PERIOD) { return; }  // rate limiting
    spin_time = getUptime();
    gpioToggle(GPIOE, GPIO_Pin_8);                           // some indication

    uint8_t buffer[UAVCAN_NODE_STATUS_MESSAGE_SIZE];
    static uint8_t transfer_id = 0;                          // This variable MUST BE STATIC; refer to the libcanard documentation for the background

    makeNodeStatusMessage(buffer);

    canardBroadcast(&canard, 
                    UAVCAN_NODE_STATUS_DATA_TYPE_SIGNATURE,
	    			UAVCAN_NODE_STATUS_DATA_TYPE_ID,
        			&transfer_id,
        			CANARD_TRANSFER_PRIORITY_LOW,
	    			buffer, 
	    			UAVCAN_NODE_STATUS_MESSAGE_SIZE);
}

...

Code Block
titlemakeNodeStatusMessage
static void makeNodeStatusMessage(uint8_t buffer[UAVCAN_NODE_STATUS_MESSAGE_SIZE])
{
	const uint8_t node_health = UAVCAN_NODE_HEALTH_OK;
	const uint8_t node_mode   = UAVCAN_NODE_MODE_OPERATIONAL;
    memset(buffer, 0, UAVCAN_NODE_STATUS_MESSAGE_SIZE);
    const uint32_t uptime_sec = get_uptime() / 1000;
    canardEncodeScalar(buffer,  0, 32, &uptime_sec);
    canardEncodeScalar(buffer, 32,  2, &node_health);
    canardEncodeScalar(buffer, 34,  3, &node_mode);
}

...

Code Block
titlecanard_get_node_info_handle
#define APP_VERSION_MAJOR   					99
#define APP_VERSION_MINOR   					99
#define APP_NODE_NAME   						"com.zubax.babel.demo"
#define GIT_HASH								0xBADC0FFE            // Normally this should be queried from the VCS when building the firmware
#define UAVCAN_GET_NODE_INFO_RESPONSE_MAX_SIZE  ((3015 + 7) / 8)

static uint16_t makeNodeInfoMessage(uint8_t buffer[UAVCAN_GET_NODE_INFO_RESPONSE_MAX_SIZE])
{
    memset(buffer, 0, UAVCAN_GET_NODE_INFO_RESPONSE_MAX_SIZE);
    makeNodeStatusMessage(buffer);

    buffer[7] = APP_VERSION_MAJOR;
    buffer[8] = APP_VERSION_MINOR;
    buffer[9] = 1;  // Optional field flags, VCS commit is set
    const uint32_t git_hash = GIT_HASH;
    canardEncodeScalar(buffer, 80, 32, &git_hash); 

    readUniqueID(&buffer[24]);
    const size_t name_len = strlen(APP_NODE_NAME);
    memcpy(&buffer[41], APP_NODE_NAME, name_len);
    return 41 + name_len ;
}

static void sendNodeInfoResponsegetNodeInfoHandleCanard(CanardRxTransfer* transfer)
{
    uint8_t buffer[UAVCAN_GET_NODE_INFO_RESPONSE_MAX_SIZE];
    memset(buffer, 0, UAVCAN_GET_NODE_INFO_RESPONSE_MAX_SIZE);
    const uint16_t len = makeNodeInfoMessage(buffer);
    int result = canardRequestOrRespond(&g_canard,
                                        transfer->source_node_id,
                                        UAVCAN_GET_NODE_INFO_DATA_TYPE_SIGNATURE,
                                        UAVCAN_GET_NODE_INFO_DATA_TYPE_ID,
                                        &transfer->transfer_id,
                                        transfer->priority,
                                        CanardResponse,
                                        &buffer[0],
                                        (uint16_t)len);
    if (result < 0)
    {
        // TODO: handle the error
    }
}

...

Code Block
titlesystick_isr
void systickISR(void);
static uint32_t getUptime(void);

static uint32_t  g_uptime = 0;

static uint32_t getUptime(void)
{
    return g_uptime;     // Atomic read, locking is not needed
}

void systickISR(void)
{
    g_uptime++;
}

...

Code Block
titlecanard_sender
static void sendCanard(void)
{
    const CanardCANFrame* txf = canardPeekTxQueue(&g_canard); 
    while(txf)
    {
        const int tx_res = canardSTM32Transmit(txf);
        if (tx_res < 0)         // Failure - drop the frame and report
        {
            __ASM volatile("BKPT #01");   // TODO: handle the error properly
        }
        if(tx_res > 0)
        {
            canardPopTxQueue(&g_canard);
        }
        txf = canardPeekTxQueue(&g_canard); 
    }
}

...

Code Block
titlecanard_receive
static void receiveCanard(void)
{
    CanardCANFrame rx_frame;
    int res = canardSTM32Receive(&rx_frame);
    if(res)
    {
        canardHandleRxFrame(&canard, &rx_frame, get_uptime() * 1000);
    }    
}

...