FlexCAN usage example

Since we included our iMX FlexCAN driver in the iMX25 Topaz image binaries we have received a couple of requests for sample code, so here it is:

#include "DebugZones.h"
#include "FlexCANSDK.h"

#define CAN_BITRATE         (125*1000)  // 125 kHz
#define CAN_READ_INTERVAL   1000        // Set to INFINITE to wait forever for a CAN Frame
#define CAN_WRITE_INTERVAL   500

CRITICAL_SECTION gCS;
LPCWSTR DataToHexString(const PCAN_FRAME pCANFrame)
{
    static WCHAR szHexString[100];
    WCHAR szHexByte[7];
    EnterCriticalSection(&gCS);
    {
        szHexString[0] = 0;
        if (pCANFrame->btDataLen)
        {
            wsprintf(szHexByte, L"0x%02X", pCANFrame->btData[0]);
            wcscat_s(szHexString, _countof(szHexString), szHexByte);
            for (int i=1; i<pCANFrame->btDataLen; i++)
            {
                wsprintf(szHexByte, L", 0x%02X", pCANFrame->btData[i]);
                wcscat_s(szHexString, _countof(szHexString), szHexByte);
            }
        }
    } LeaveCriticalSection(&gCS);
    return szHexString;
}

DWORD WINAPI CANReadThread(LPVOID lpParameter)
{
    HANDLE hFinishEvent = (HANDLE)lpParameter;
    CAN_FRAME canFrame = {0};
    canFrame.bExtended = CAN_EXTENDED;  // Receive any extended frame
    LOGMSG(ZONE_INFO, L"CAN Read Thread initialized; waiting for %s CAN frames...\r\n", (CAN_EXTENDED == canFrame.bExtended) ? L"Extended" : L"Standard");
    do
    {
        if (ERROR_SUCCESS == FlexCANReadFrame(1, &canFrame, CAN_READ_INTERVAL, 0))
        {   // Convert data to string, copy the string and show received frame
            LPWSTR pszData = wcsdup(DataToHexString(&canFrame));
            if (canFrame.bExtended == CAN_EXTENDED)
                LOGMSG(ZONE_INFO, L"Read CAN frame with ID 0x%08X, Data: %s\r\n", canFrame.ui32ID, pszData);
            else
                LOGMSG(ZONE_INFO, L"Read CAN frame with ID 0x%03X, Data: %s\r\n", canFrame.ui32ID, pszData);
            // Clean up
            free(pszData);
        }
    } while (WAIT_TIMEOUT == WaitForSingleObject(hFinishEvent, 0));

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    // Register with debug subsystem
    RETAILREGISTERZONES(NULL);

    InitializeCriticalSection(&gCS);

    HANDLE hFinishEvent = NULL;
    HANDLE hReadThread = NULL;
    for (;;)
    {   // Use loop for easy break-out error handling
        if (!FlexCANInit(1))
            break;

        DWORD dwBitrate = CAN_BITRATE;
        if (!FlexCANSetBitrate(1, &dwBitrate))
            break;
        LOGMSG(ZONE_INFO, L"Bitrate set to %d (requested %d)\r\n", dwBitrate, CAN_BITRATE);

        hFinishEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        if (!hFinishEvent)
            break;

        // Create the read thread that will receive all CAN Frames
        hReadThread = CreateThread(NULL, 0, CANReadThread, (LPVOID)hFinishEvent, 0, NULL);
        if (!hReadThread)
            break;

        // Some time to see CAN Frames coming in
        Sleep(10000);

        CAN_FRAME canFrame = {0};
        for (int i=0; i<10; i++)
        {   // Send a couple of frames at highest priority (0)
            canFrame.bExtended = CAN_EXTENDED;
            canFrame.btData[0] = 0x10;
            canFrame.btData[1] = 0x11;
            canFrame.btData[2] = 0x12;
            canFrame.btDataLen = 3;
            canFrame.ui32ID = 0x12345678;
            DWORD dwRet = FlexCANWriteFrame(1, CAN_DATA, CAN_TXNOW, 0, &canFrame, 500);
            LOGMSG(ZONE_INFO, L"Frame with ID 0x%08X and data %s sent. Result: %d\r\n", canFrame.ui32ID, DataToHexString(&canFrame), dwRet);
            Sleep(CAN_WRITE_INTERVAL);
        }

        // Signal read thread to finish
        SetEvent(hFinishEvent);
        if (WAIT_OBJECT_0 != WaitForSingleObject(hReadThread, CAN_READ_INTERVAL*2))
            TerminateThread(hReadThread, 0);

        // And wait for a frame with ID 0x12345678 for 10 seconds (no other CAN frames are accepted during this time)
        canFrame.bExtended = CAN_EXTENDED;
        canFrame.ui32ID = 0x12345678;
        LOGMSG(ZONE_INFO, L"Waiting for extended frame with ID 0x%08X...\r\n", canFrame.ui32ID);
        DWORD dwRet = FlexCANReadFrame(1, &canFrame, 10000, 0x1FFFFFFF);
        LOGMSG(ZONE_INFO, L"Specific FlexCANReadFrame result: %d\r\n", dwRet);
        if (ERROR_SUCCESS == dwRet)
            LOGMSG(ZONE_INFO, L"Read CAN frame with ID 0x%08X, Data: %s\r\n", canFrame.ui32ID, DataToHexString(&canFrame));

        // Now read any frame (ui32IDMask set to 0)
        LOGMSG(ZONE_INFO, L"Waiting for extended frame with any ID...\r\n");
        dwRet = FlexCANReadFrame(1, &canFrame, 10000, 0);
        LOGMSG(ZONE_INFO, L"Unspecific FlexCANReadFrame result: %d\r\n", dwRet);
        if (ERROR_SUCCESS == dwRet)
        {   // Show received frame
            if (canFrame.bExtended == CAN_EXTENDED)
                LOGMSG(ZONE_INFO, L"Read CAN frame with ID 0x%08X, Data: %s\r\n", canFrame.ui32ID, DataToHexString(&canFrame));
            else
                LOGMSG(ZONE_INFO, L"Read CAN frame with ID 0x%03X, Data: %s\r\n", canFrame.ui32ID, DataToHexString(&canFrame));
        }

        // Now transfer a whole bunch of messages in one go
        CAN_TRANSFER_BLOCK canBlock;
        canBlock.dwNumPackets = 32;
        canBlock.pCANPackets = new CAN_PACKET[canBlock.dwNumPackets];
        if (canBlock.pCANPackets)
        {
            for (DWORD i=0; i<canBlock.dwNumPackets; i++)
            {   // Init packets; data from max to 0
                canBlock.pCANPackets[i].bRemote = CAN_DATA;             // Data frame
                canBlock.pCANPackets[i].btIndex = 0xFF;                 // Let driver find a free message buffer
                canBlock.pCANPackets[i].btPriority = 0;                 // Highest priority
                canBlock.pCANPackets[i].bTxOnRemoteRx = CAN_TXNOW;      // Transfer immediately
                canBlock.pCANPackets[i].bWrite = CAN_WRITE;             // We want to write this frame
                canBlock.pCANPackets[i].canFrame.bExtended = CAN_STANDARD;  // Standard address (11 bit)
                canBlock.pCANPackets[i].canFrame.btData[0] = (BYTE)(0xFF - (i*(256/canBlock.dwNumPackets)));
                canBlock.pCANPackets[i].canFrame.btDataLen = 1;         // 1 byte data
                canBlock.pCANPackets[i].canFrame.ui32ID = 0x123;        // Address
                canBlock.pCANPackets[i].dwTimeout = 100;                // Write timeout
            }
            BOOL bRet = FlexCANTransfer(1, &canBlock);
            LOGMSG(ZONE_INFO, L"FlexCANTransfer result: %s\r\n", bRet ? L"TRUE" : L"FALSE");
            for (DWORD i=0; i<canBlock.dwNumPackets; i++)
                LOGMSG(ZONE_INFO, L"Individual transmit %d transmit result: %d\r\n", i, canBlock.pCANPackets[i].dwError);
        }

        // Now write a frame after receiving a remote request with the same ID
        canFrame.bExtended = CAN_EXTENDED;
        canFrame.btData[0] = 0x12;
        canFrame.btData[1] = 0x11;
        canFrame.btData[2] = 0x10;
        canFrame.btDataLen = 3;
        canFrame.ui32ID = 0x7654321;
        LOGMSG(ZONE_INFO, L"Waiting for remote request with ID 0x%08X...\r\n", canFrame.ui32ID);
        dwRet = FlexCANWriteFrame(1, CAN_DATA, CAN_TXONREMOTERX, 0, &canFrame, 10000);
        LOGMSG(ZONE_INFO, L"Frame with ID 0x%08X and data %s sent. Result: %d\r\n", canFrame.ui32ID, DataToHexString(&canFrame), dwRet);

        // Always exit out of loop
        break;
    }

    //Clean up
    FlexCANDeinit(1);

    if (hFinishEvent)
        CloseHandle(hFinishEvent);
    if (hReadThread)
        CloseHandle(hReadThread);

    DeleteCriticalSection(&gCS);

    return 0;
}

The code above is using our standard FlexCAN driver functionality and uses our (free downloadable) debug message templates for debug logging. Our High Performance FlexCAN driver supports complex ID filtering setups and a high speed (virtually unlimited) receive FIFO, among many more features.