/************************************************************************************//** * \file leaflight.c * \brief Kvaser Leaf Light v2 interface source file. * \ingroup Kvaser_LeafLight * \internal *---------------------------------------------------------------------------------------- * C O P Y R I G H T *---------------------------------------------------------------------------------------- * Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved * *---------------------------------------------------------------------------------------- * L I C E N S E *---------------------------------------------------------------------------------------- * This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any later * version. * * OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You have received a copy of the GNU General Public License along with OpenBLT. It * should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy. * * \endinternal ****************************************************************************************/ /**************************************************************************************** * Include files ****************************************************************************************/ #include /* for assertions */ #include /* for standard integer types */ #include /* for NULL declaration */ #include /* for boolean type */ #include /* for standard library */ #include /* for string library */ #include "candriver.h" /* Generic CAN driver module */ #include "leaflight.h" /* Kvaser Leaf Light v2 interface */ #include /* for Windows API */ /*lint -efile(537, pshpack1.h, poppack.h) */ /*lint -efile(451, pshpack1.h, poppack.h) */ #include "canlib.h" /* for Kvaser CANLIB API */ /*************************************************************************************** * Type definitions ****************************************************************************************/ /* Type definitions of the functions in the Kvaser CANLIB API that this CAN interface * uses. */ typedef void (__stdcall * tLeafLightLibFuncInitializeLibrary)(void); typedef canStatus (__stdcall * tLeafLightLibFuncUnloadLibrary)(void); typedef CanHandle (__stdcall * tLeafLightLibFuncOpenChannel)(int32_t channel, int32_t flags); typedef canStatus (__stdcall * tLeafLightLibFuncSetBusParams)(const CanHandle hnd, int32_t freq, uint32_t tseg1, uint32_t tseg2, uint32_t sjw, uint32_t noSamp, uint32_t syncmode); typedef canStatus (__stdcall * tLeafLightLibFuncSetBusOutputControl)(const CanHandle hnd, const uint32_t drivertype); typedef canStatus (__stdcall * tLeafLightLibFuncSetAcceptanceFilter)(const CanHandle hnd, uint32_t code, uint32_t mask, int32_t is_extended); typedef canStatus (__stdcall * tLeafLightLibFuncIoCtl)(const CanHandle hnd, uint32_t func, void * buf, uint32_t buflen); typedef canStatus (__stdcall * tLeafLightLibFuncBusOn)(const CanHandle hnd); typedef canStatus (__stdcall * tLeafLightLibFuncWrite)(const CanHandle hnd, int32_t id, void * msg, uint32_t dlc, uint32_t flag); typedef canStatus (__stdcall * tLeafLightLibFuncRead)(const CanHandle hnd, int32_t * id, void * msg, uint32_t * dlc, uint32_t * flag, uint32_t * time); typedef canStatus (__stdcall * tLeafLightLibFuncReadStatus)(const CanHandle hnd, uint32_t * const flags); typedef canStatus (__stdcall * tLeafLightLibFuncBusOff)(const CanHandle hnd); typedef canStatus (__stdcall * tLeafLightLibFuncClose)(const CanHandle hnd); /*************************************************************************************** * Function prototypes ****************************************************************************************/ /* CAN interface functions. */ static void LeafLightInit(tCanSettings const * settings); static void LeafLightTerminate(void); static bool LeafLightConnect(void); static void LeafLightDisconnect(void); static bool LeafLightTransmit(tCanMsg const * msg); static bool LeafLightIsBusError(void); static void LeafLightRegisterEvents(tCanEvents const * events); /* CAN message reception thread. */ static DWORD WINAPI LeafLightReceptionThread(LPVOID pv); /* Kvaser CANLIB library handling. */ static void LeafLightLibLoadDll(void); static void LeafLightLibUnloadDll(void); static void LeafLightLibFuncInitializeLibrary(void); static canStatus LeafLightLibFuncUnloadLibrary(void); static CanHandle LeafLightLibFuncOpenChannel(int32_t channel, int32_t flags); static canStatus LeafLightLibFuncSetBusParams(const CanHandle hnd, int32_t freq, uint32_t tseg1, uint32_t tseg2, uint32_t sjw, uint32_t noSamp, uint32_t syncmode); static canStatus LeafLightLibFuncSetBusOutputControl(const CanHandle hnd, const uint32_t drivertype); static canStatus LeafLightLibFuncSetAcceptanceFilter(const CanHandle hnd, uint32_t code, uint32_t mask, int32_t is_extended); static canStatus LeafLightLibFuncIoCtl(const CanHandle hnd, uint32_t func, void * buf, uint32_t buflen); static canStatus LeafLightLibFuncBusOn(const CanHandle hnd); static canStatus LeafLightLibFuncWrite(const CanHandle hnd, int32_t id, void * msg, uint32_t dlc, uint32_t flag); static canStatus LeafLightLibFuncRead(const CanHandle hnd, int32_t * id, void * msg, uint32_t * dlc, uint32_t * flag, uint32_t * time); static canStatus LeafLightLibFuncReadStatus(const CanHandle hnd, uint32_t * const flags); static canStatus LeafLightLibFuncBusOff(const CanHandle hnd); static canStatus LeafLightLibFuncClose(const CanHandle hnd); /**************************************************************************************** * Local constant declarations ****************************************************************************************/ /** \brief CAN interface structure filled with Kvaser Leaf Light v2 specifics. */ static const tCanInterface leafLightInterface = { LeafLightInit, LeafLightTerminate, LeafLightConnect, LeafLightDisconnect, LeafLightTransmit, LeafLightIsBusError, LeafLightRegisterEvents }; /**************************************************************************************** * Local data declarations ****************************************************************************************/ /** \brief The settings to use in this CAN interface. */ static tCanSettings leafLightSettings; /** \brief List with callback functions that this driver should use. */ static tCanEvents * leafLightEventsList; /** \brief Total number of event entries into the \ref leafLightEventsList list. */ static uint32_t leafLightEventsEntries; /** \brief Handle to the Kvaser CANLIB dynamic link library. */ static HINSTANCE leafLightDllHandle; /** \brief Handle to the CAN channel. */ static CanHandle leafLightCanHandle; /** \brief Handle to the CAN channel for usage in the CAN reception thread. */ static CanHandle leafLightRxCanHandle; /** \brief Function pointer to the Kvaser CANLIB canInitializeLibrary function. */ static tLeafLightLibFuncInitializeLibrary leafLightLibFuncInitializeLibraryPtr; /** \brief Function pointer to the Kvaser CANLIB canUnloadLibrary function. */ static tLeafLightLibFuncUnloadLibrary leafLightLibFuncUnloadLibraryPtr; /** \brief Function pointer to the Kvaser CANLIB canOpenChannel function. */ static tLeafLightLibFuncOpenChannel leafLightLibFuncOpenChannelPtr; /** \brief Function pointer to the Kvaser CANLIB canSetBusParams function. */ static tLeafLightLibFuncSetBusParams leafLightLibFuncSetBusParamsPtr; /** \brief Function pointer to the Kvaser CANLIB canSetBusOutputControl function. */ static tLeafLightLibFuncSetBusOutputControl leafLightLibFuncSetBusOutputControlPtr; /** \brief Function pointer to the Kvaser CANLIB canSetAcceptanceFilter function. */ static tLeafLightLibFuncSetAcceptanceFilter leafLightLibFuncSetAcceptanceFilterPtr; /** \brief Function pointer to the Kvaser CANLIB canIoCtl function. */ static tLeafLightLibFuncIoCtl leafLightLibFuncIoCtlPtr; /** \brief Function pointer to the Kvaser CANLIB canBusOn function. */ static tLeafLightLibFuncBusOn leafLightLibFuncBusOnPtr; /** \brief Function pointer to the Kvaser CANLIB canWrite function. */ static tLeafLightLibFuncWrite leafLightLibFuncWritePtr; /** \brief Function pointer to the Kvaser CANLIB canRead function. */ static tLeafLightLibFuncRead leafLightLibFuncReadPtr; /** \brief Function pointer to the Kvaser CANLIB canReadStatus function. */ static tLeafLightLibFuncReadStatus leafLightLibFuncReadStatusPtr; /** \brief Function pointer to the Kvaser CANLIB canBusOff function. */ static tLeafLightLibFuncBusOff leafLightLibFuncBusOffPtr; /** \brief Function pointer to the Kvaser CANLIB canClose function. */ static tLeafLightLibFuncClose leafLightLibFuncClosePtr; /** \brief Handle for the event to terminate the reception thread. */ static HANDLE leafLightTerminateEvent; /** \brief Handle for a CAN related event. */ static HANDLE leafLightCanEvent; /** \brief Handle for the CAN reception thread. */ static HANDLE leafLightRxThreadHandle; /***********************************************************************************//** ** \brief Obtains a pointer to the CAN interface structure, so that it can be linked ** to the generic CAN driver module. ** \return Pointer to CAN interface structure. ** ****************************************************************************************/ tCanInterface const * LeafLightGetInterface(void) { return &leafLightInterface; } /*** end of LeafLightGetInterface ***/ /************************************************************************************//** ** \brief Initializes the CAN interface. ** \param settings Pointer to the CAN interface settings. ** ****************************************************************************************/ static void LeafLightInit(tCanSettings const * settings) { char * canDeviceName; /* Initialize locals. */ leafLightEventsList = NULL; leafLightEventsEntries = 0; leafLightTerminateEvent = NULL; leafLightCanEvent = NULL; leafLightRxThreadHandle = NULL; leafLightDllHandle = NULL; leafLightCanHandle = -1; leafLightRxCanHandle = -1; /* Reset library function pointers. */ leafLightLibFuncInitializeLibraryPtr = NULL; leafLightLibFuncUnloadLibraryPtr = NULL; leafLightLibFuncOpenChannelPtr = NULL; leafLightLibFuncSetBusParamsPtr = NULL; leafLightLibFuncSetBusOutputControlPtr = NULL; leafLightLibFuncSetAcceptanceFilterPtr = NULL; leafLightLibFuncIoCtlPtr = NULL; leafLightLibFuncBusOnPtr = NULL; leafLightLibFuncWritePtr = NULL; leafLightLibFuncReadPtr = NULL; leafLightLibFuncReadStatusPtr = NULL; leafLightLibFuncBusOffPtr = NULL; leafLightLibFuncClosePtr = NULL; /* Reset CAN interface settings. */ leafLightSettings.devicename = ""; leafLightSettings.channel = 0; leafLightSettings.baudrate = CAN_BR500K; leafLightSettings.code = 0x00000000u; leafLightSettings.mask = 0x00000000u; /* Check parameters. */ assert(settings != NULL); /* Only continue with valid parameters. */ if (settings != NULL) /*lint !e774 */ { /* Shallow copy the CAN interface settings for later usage. */ leafLightSettings = *settings; /* The devicename is a pointer and it is not gauranteed that it stays valid so we need * to deep copy this one. note the +1 for '\0' in malloc. */ assert(settings->devicename != NULL); if (settings->devicename != NULL) /*lint !e774 */ { canDeviceName = malloc(strlen(settings->devicename) + 1); assert(canDeviceName != NULL); if (canDeviceName != NULL) /*lint !e774 */ { strcpy(canDeviceName, settings->devicename); leafLightSettings.devicename = canDeviceName; } } /* Perform initialization of Kvaser Leaf Light API. */ LeafLightLibLoadDll(); LeafLightLibFuncInitializeLibrary(); } } /*** end of LeafLightInit ***/ /************************************************************************************//** ** \brief Terminates the CAN interface. ** ****************************************************************************************/ static void LeafLightTerminate(void) { /* Perform termination of Kvaser Leaf Light API. */ (void)LeafLightLibFuncUnloadLibrary(); LeafLightLibUnloadDll(); /* Release memory that was allocated for storing the device name. */ if (leafLightSettings.devicename != NULL) { free((char *)leafLightSettings.devicename); } /* Reset CAN interface settings. */ leafLightSettings.devicename = ""; leafLightSettings.channel = 0; leafLightSettings.baudrate = CAN_BR500K; leafLightSettings.code = 0x00000000u; leafLightSettings.mask = 0x00000000u; /* Release memory that was allocated for CAN events and reset the entry count. */ if ( (leafLightEventsList != NULL) && (leafLightEventsEntries != 0) ) { free(leafLightEventsList); leafLightEventsEntries = 0; } } /*** end of LeafLightTerminate ***/ /************************************************************************************//** ** \brief Connects the CAN interface. ** \return True if connected, false otherwise. ** ****************************************************************************************/ static bool LeafLightConnect(void) { bool result = false; bool baudrateSupported = true; int32_t frequency = 0; uint32_t tseg1 = 0; uint32_t tseg2 = 0; uint32_t sjw = 0; uint32_t noSamp = 0; /* Convert the baudrate to a value supported by the PCAN-Basic API. */ switch (leafLightSettings.baudrate) { case CAN_BR10K: frequency = canBITRATE_10K; break; case CAN_BR20K: frequency = 20000; tseg1 = 5; tseg2 = 2; sjw = 2; noSamp = 1; break; case CAN_BR50K: frequency = canBITRATE_50K; break; case CAN_BR100K: frequency = canBITRATE_100K; break; case CAN_BR125K: frequency = canBITRATE_125K; break; case CAN_BR250K: frequency = canBITRATE_250K; break; case CAN_BR500K: frequency = canBITRATE_500K; break; case CAN_BR800K: frequency = 800000; tseg1 = 6; tseg2 = 3; sjw = 2; noSamp = 1; break; case CAN_BR1M: frequency = canBITRATE_1M; break; default: baudrateSupported = false; break; } /* Note that the device name itself is not needed anymore at this point, it was only * needed by the CAN driver to link the correct interface (this one). The channel is * also don't care as the adapter only has one channel. Check settings. */ assert(baudrateSupported); /* Invalidate handles. */ leafLightCanHandle = -1; leafLightRxCanHandle = -1; leafLightTerminateEvent = NULL; leafLightCanEvent = NULL; leafLightRxThreadHandle = NULL; /* Only continue with valid settings. */ if (baudrateSupported) { /* Init result code to success and only negate it on detection of error. */ result = true; /* Open the CAN channel with support for both 11- and 29-bit CAN identifiers, and * obtain its handle. */ leafLightCanHandle = LeafLightLibFuncOpenChannel(0, canOPEN_REQUIRE_INIT_ACCESS | canOPEN_REQUIRE_EXTENDED); /* Validate the handle. */ if (leafLightCanHandle < 0) { result = false; } /* Configure the baudrate. */ if (result) { if (LeafLightLibFuncSetBusParams(leafLightCanHandle, frequency, tseg1, tseg2, sjw, noSamp, 0) != canOK) { result = false; } } /* Set output control to the default normal mode. */ if (result) { if (LeafLightLibFuncSetBusOutputControl(leafLightCanHandle, canDRIVER_NORMAL) != canOK) { result = false; } } /* Configure reception acceptance filter. */ if ( (result) && (leafLightSettings.mask != 0x00000000u) ) { /* Start out by closing the acceptance filters first. */ if (LeafLightLibFuncSetAcceptanceFilter(leafLightCanHandle, 0x00000000u, 0x00000000u, 0) != canOK) { result = false; } if (result) { if (LeafLightLibFuncSetAcceptanceFilter(leafLightCanHandle, 0x00000000u, 0x00000000u, 1) != canOK) { result = false; } } if (result) { /* Use bit logic to determine if the filter should accept standard 11-bit and/or * extended 29-bit identifiers: * acceptStdId = ((mask & code & CAN_MSG_EXT_ID_MASK) == 0) * acceptExtId = ((mask & code & CAN_MSG_EXT_ID_MASK) != 0) || * ((mask & CAN_MSG_EXT_ID_MASK) == 0) */ bool acceptStdID = ((leafLightSettings.mask & leafLightSettings.code & CAN_MSG_EXT_ID_MASK) == 0); bool acceptExtID = ((leafLightSettings.mask & leafLightSettings.code & CAN_MSG_EXT_ID_MASK) != 0) || ((leafLightSettings.mask & CAN_MSG_EXT_ID_MASK) == 0); /* Configure acceptance filter for standard 11-bit identifiers. */ if (acceptStdID) { if (LeafLightLibFuncSetAcceptanceFilter(leafLightCanHandle, leafLightSettings.code & 0x1fffffffu, leafLightSettings.mask & 0x1fffffffu, 0) != canOK) { result = false; } } /* Configure acceptance filter for extended 29-bit identifiers. */ if ((acceptExtID) && (result)) { if (LeafLightLibFuncSetAcceptanceFilter(leafLightCanHandle, leafLightSettings.code & 0x1fffffffu, leafLightSettings.mask & 0x1fffffffu, 1) != canOK) { result = false; } } } } /* Go on the bus. */ if (result) { if (LeafLightLibFuncBusOn(leafLightCanHandle) != canOK) { result = false; } } /* Open the CAN channel and obtain its handle, which will only be used in the * reception thread. CAN channel handles are not thread safe and therefore a * second handle is needed. Note that no init access is needed for this * handle. */ leafLightRxCanHandle = LeafLightLibFuncOpenChannel(0, canOPEN_NO_INIT_ACCESS); /* Validate the handle. */ if (leafLightRxCanHandle < 0) { result = false; } /* Go on the bus. */ if (result) { if (LeafLightLibFuncBusOn(leafLightRxCanHandle) != canOK) { result = false; } } /* Obtain the handle for CAN events. */ if (result) { leafLightCanEvent = NULL; if (LeafLightLibFuncIoCtl(leafLightRxCanHandle, canIOCTL_GET_EVENTHANDLE, &leafLightCanEvent, sizeof(leafLightCanEvent)) != canOK) { result = false; } /* Validate the handle. */ if (leafLightCanEvent == NULL) { result = false; } } /* Create the terminate event handle used in the reception thread. */ if (result) { leafLightTerminateEvent = CreateEvent(NULL, TRUE, FALSE, ""); if (leafLightTerminateEvent == NULL) { result = false; } } /* Start the reception thread as the last step. */ if (result) { leafLightRxThreadHandle = CreateThread(NULL, 0, LeafLightReceptionThread, NULL, 0, NULL); if (leafLightRxThreadHandle == NULL) { result = false; } } } /* Clean-up in case an error occurred. */ if (!result) { if (leafLightCanHandle >= 0) { /* Go off the bus and close the channel. */ (void)LeafLightLibFuncBusOff(leafLightCanHandle); (void)LeafLightLibFuncClose(leafLightCanHandle); leafLightCanHandle = -1; } if (leafLightRxCanHandle >= 0) { /* Go off the bus and close the channel. */ (void)LeafLightLibFuncBusOff(leafLightRxCanHandle); (void)LeafLightLibFuncClose(leafLightRxCanHandle); leafLightRxCanHandle = -1; } if (leafLightTerminateEvent != NULL) { /* Close the event handle. */ (void)CloseHandle(leafLightTerminateEvent); leafLightTerminateEvent = NULL; } } /* Give the result back to the caller. */ return result; } /*** end of LeafLightConnect ***/ /************************************************************************************//** ** \brief Disconnects the CAN interface. ** ****************************************************************************************/ static void LeafLightDisconnect(void) { /* Stop the reception thread. */ if (leafLightRxThreadHandle != NULL) { /* Trigger event to request the reception thread to stop. */ (void)SetEvent(leafLightTerminateEvent); /* Wait for the thread to signal termination. */ (void)WaitForSingleObject(leafLightRxThreadHandle, INFINITE); /* Close the thread handle. */ (void)CloseHandle(leafLightRxThreadHandle); leafLightRxThreadHandle = NULL; } /* Close the terminate event handle. */ if (leafLightTerminateEvent != NULL) { (void)CloseHandle(leafLightTerminateEvent); leafLightTerminateEvent = NULL; } /* Go off the bus and close the channel. */ if (leafLightCanHandle >= 0) { (void)LeafLightLibFuncBusOff(leafLightCanHandle); (void)LeafLightLibFuncClose(leafLightCanHandle); leafLightCanHandle = -1; } if (leafLightRxCanHandle >= 0) { (void)LeafLightLibFuncBusOff(leafLightRxCanHandle); (void)LeafLightLibFuncClose(leafLightRxCanHandle); leafLightRxCanHandle = -1; } } /*** end of LeafLightDisconnect ***/ /************************************************************************************//** ** \brief Submits a message for transmission on the CAN bus. ** \param msg Pointer to CAN message structure. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool LeafLightTransmit(tCanMsg const * msg) { bool result = false; tCanEvents const * pEvents; int32_t txId; uint32_t txFlags; uint8_t txData[CAN_MSG_MAX_LEN]; /* Check parameters. */ assert(msg != NULL); /* Only continue with valid parameters and handle. */ if ( (msg != NULL) && (leafLightCanHandle >= 0) ) /*lint !e774 */ { /* Prepare message. */ if ((msg->id & CAN_MSG_EXT_ID_MASK) == 0) { txId = msg->id & 0x7ffu; txFlags = canMSG_STD; } else { txId = msg->id & 0x1fffffffu; txFlags = canMSG_EXT; } for (uint8_t idx = 0; idx < msg->dlc; idx++) { txData[idx] = msg->data[idx]; } /* Submit CAN message for transmission. */ if (LeafLightLibFuncWrite(leafLightCanHandle, txId, txData, msg->dlc, txFlags) == canOK) { /* Update result value to success. */ result = true; /* Trigger transmit complete event(s). */ pEvents = leafLightEventsList; for (uint32_t idx = 0; idx < leafLightEventsEntries; idx++) { if (pEvents != NULL) { if (pEvents->MsgTxed != NULL) { pEvents->MsgTxed(msg); } /* Move on to the next entry in the list. */ pEvents++; } } } } /* Give the result back to the caller. */ return result; } /*** end of LeafLightTransmit ***/ /************************************************************************************//** ** \brief Checks if a bus off or bus heavy situation occurred. ** \return True if a bus error situation was detected, false otherwise. ** ****************************************************************************************/ static bool LeafLightIsBusError(void) { bool result = false; uint32_t statusFlags; /* Only continue with valid handle. */ if (leafLightCanHandle >= 0) { /* Read the status flags. */ if (LeafLightLibFuncReadStatus(leafLightCanHandle, &statusFlags) == canOK) { /* Check for bus off or error passive bits. */ if ((statusFlags & (canSTAT_BUS_OFF | canSTAT_ERROR_PASSIVE)) != 0) { result = true; } } } /* Give the result back to the caller. */ return result; } /*** end of LeafLightIsBusError ***/ /************************************************************************************//** ** \brief Registers the event callback functions that should be called by the CAN ** interface. ** \param events Pointer to structure with event callback function pointers. ** ****************************************************************************************/ static void LeafLightRegisterEvents(tCanEvents const * events) { /* Check parameters. */ assert(events != NULL); /* Only continue with valid parameters. */ if (events != NULL) /*lint !e774 */ { /* Increase length of the list to make space for one more event entry. Note that * it is okay to call realloc with a NULL pointer. In this case it simply behaves * as malloc. */ leafLightEventsList = realloc(leafLightEventsList, (sizeof(tCanEvents) * (leafLightEventsEntries + 1))); /* Assert reallocation. */ assert(leafLightEventsList != NULL); /* Only continue if reallocation was successful. */ if (leafLightEventsList != NULL) { /* Increment events entry count. */ leafLightEventsEntries++; /* Store the events in the new entry. */ leafLightEventsList[leafLightEventsEntries - 1] = *events; } /* Reallocation failed. */ else { /* Reset events entry count. */ leafLightEventsEntries = 0; } } } /*** end of LeafLightRegisterEvents ***/ /************************************************************************************//** ** \brief CAN message reception thread. ** \param pv Pointer to thread parameters. ** \return Thread exit code. ** ****************************************************************************************/ static DWORD WINAPI LeafLightReceptionThread(LPVOID pv) { DWORD waitResult; HANDLE handles[] = { leafLightCanEvent, leafLightTerminateEvent }; bool running = true; int32_t rxId; uint32_t rxDlc; uint32_t rxTime; uint32_t rxFlags; tCanMsg rxMsg; canStatus rxStatus; tCanEvents const * pEvents; /* Parameter not used. */ (void)pv; /* Enter thread's infinite loop. */ while (running) { waitResult = WaitForMultipleObjects(sizeof(handles)/sizeof(handles[0]), handles, FALSE, INFINITE); switch (waitResult) { /* CAN reception event. */ case WAIT_OBJECT_0 + 0: /*lint !e835 */ /* Only read out the events when the handle is valid. */ if (leafLightRxCanHandle >= 0) { /* Empty out the event queue. */ do { rxStatus = LeafLightLibFuncRead(leafLightRxCanHandle, &rxId, &rxMsg.data[0], &rxDlc, &rxFlags, &rxTime); /* Only process the result if a message was read. */ if (rxStatus == canOK) { /* Only process STD and EXT messages. */ if ((rxFlags & (canMSG_STD | canMSG_EXT)) != 0) { /* Convert the CAN message to the format of the CAN driver module. Note * that the data was already copied by LeafLightLibFuncRead(). */ rxMsg.id = (uint32_t)rxId; if ((rxFlags & canMSG_EXT) != 0) { rxMsg.id |= CAN_MSG_EXT_ID_MASK; } rxMsg.dlc = (uint8_t)rxDlc; /* Trigger message reception event(s). */ pEvents = leafLightEventsList; for (uint32_t idx = 0; idx < leafLightEventsEntries; idx++) { if (pEvents != NULL) { if (pEvents->MsgRxed != NULL) { pEvents->MsgRxed(&rxMsg); } /* Move on to the next entry in the list. */ pEvents++; } } } } } while (rxStatus != canERR_NOMSG); } break; /* Termination event. */ default: case WAIT_OBJECT_0 + 1: /*lint !e835 */ /* Stop thread. */ running = false; break; } } /* Exit thread. */ return 0; } /*** end of LeafLightReceptionThread ***/ /************************************************************************************//** ** \brief Loads the Kvaser CANLIB DLL and initializes the API function pointers. ** ****************************************************************************************/ static void LeafLightLibLoadDll(void) { /* Reset the channel handles. */ leafLightCanHandle = -1; leafLightRxCanHandle = -1; /* Start out by resetting the API function pointers. */ leafLightLibFuncInitializeLibraryPtr = NULL; leafLightLibFuncUnloadLibraryPtr = NULL; leafLightLibFuncOpenChannelPtr = NULL; leafLightLibFuncSetBusParamsPtr = NULL; leafLightLibFuncSetBusOutputControlPtr = NULL; leafLightLibFuncSetAcceptanceFilterPtr = NULL; leafLightLibFuncIoCtlPtr = NULL; leafLightLibFuncBusOnPtr = NULL; leafLightLibFuncWritePtr = NULL; leafLightLibFuncReadPtr = NULL; leafLightLibFuncReadStatusPtr = NULL; leafLightLibFuncBusOffPtr = NULL; leafLightLibFuncClosePtr = NULL; /* Attempt to load the library and obtain a handle to it. */ leafLightDllHandle = LoadLibrary("canlib32"); /* Assert libary handle. */ assert(leafLightDllHandle != NULL); /* Only continue if the library was successfully loaded */ if (leafLightDllHandle != NULL) /*lint !e774 */ { /* Set canInitializeLibrary function pointer. */ leafLightLibFuncInitializeLibraryPtr = (tLeafLightLibFuncInitializeLibrary)GetProcAddress(leafLightDllHandle, "canInitializeLibrary"); /* Set canUnloadLibrary function pointer. */ leafLightLibFuncUnloadLibraryPtr = (tLeafLightLibFuncUnloadLibrary)GetProcAddress(leafLightDllHandle, "canUnloadLibrary"); /* Set canOpenChannel function pointer. */ leafLightLibFuncOpenChannelPtr = (tLeafLightLibFuncOpenChannel)GetProcAddress(leafLightDllHandle, "canOpenChannel"); /* Set canSetBusParams function pointer. */ leafLightLibFuncSetBusParamsPtr = (tLeafLightLibFuncSetBusParams)GetProcAddress(leafLightDllHandle, "canSetBusParams"); /* Set canSetBusOutputControl function pointer. */ leafLightLibFuncSetBusOutputControlPtr = (tLeafLightLibFuncSetBusOutputControl)GetProcAddress(leafLightDllHandle, "canSetBusOutputControl"); /* Set canAccept function pointer. */ leafLightLibFuncSetAcceptanceFilterPtr = (tLeafLightLibFuncSetAcceptanceFilter)GetProcAddress(leafLightDllHandle, "canSetAcceptanceFilter"); /* Set canIoCtl function pointer. */ leafLightLibFuncIoCtlPtr = (tLeafLightLibFuncIoCtl)GetProcAddress(leafLightDllHandle, "canIoCtl"); /* Set canBusOn function pointer. */ leafLightLibFuncBusOnPtr = (tLeafLightLibFuncBusOn)GetProcAddress(leafLightDllHandle, "canBusOn"); /* Set canWrite function pointer. */ leafLightLibFuncWritePtr = (tLeafLightLibFuncWrite)GetProcAddress(leafLightDllHandle, "canWrite"); /* Set canRead function pointer. */ leafLightLibFuncReadPtr = (tLeafLightLibFuncRead)GetProcAddress(leafLightDllHandle, "canRead"); /* Set canReadStatus function pointer. */ leafLightLibFuncReadStatusPtr = (tLeafLightLibFuncReadStatus)GetProcAddress(leafLightDllHandle, "canReadStatus"); /* Set canBusOff function pointer. */ leafLightLibFuncBusOffPtr = (tLeafLightLibFuncBusOff)GetProcAddress(leafLightDllHandle, "canBusOff"); /* Set canClose function pointer. */ leafLightLibFuncClosePtr = (tLeafLightLibFuncClose)GetProcAddress(leafLightDllHandle, "canClose"); } } /*** end of LeafLightLibLoadDll ***/ /************************************************************************************//** ** \brief Unloads the Kvaser CANLIB DLL and resets the API function pointers. ** ****************************************************************************************/ static void LeafLightLibUnloadDll(void) { /* Reset the API function pointers. */ leafLightLibFuncInitializeLibraryPtr = NULL; leafLightLibFuncUnloadLibraryPtr = NULL; leafLightLibFuncOpenChannelPtr = NULL; leafLightLibFuncSetBusParamsPtr = NULL; leafLightLibFuncSetBusOutputControlPtr = NULL; leafLightLibFuncSetAcceptanceFilterPtr = NULL; leafLightLibFuncIoCtlPtr = NULL; leafLightLibFuncBusOnPtr = NULL; leafLightLibFuncWritePtr = NULL; leafLightLibFuncReadPtr = NULL; leafLightLibFuncReadStatusPtr = NULL; leafLightLibFuncBusOffPtr = NULL; leafLightLibFuncClosePtr = NULL; /* Reset the channel handles. */ leafLightCanHandle = -1; leafLightRxCanHandle = -1; /* Unload the library and invalidate its handle. */ if (leafLightDllHandle != NULL) { (void)FreeLibrary(leafLightDllHandle); leafLightDllHandle = NULL; } } /*** end of LeafLightLibUnloadDll **/ /************************************************************************************//** ** \brief This function must be called before any other functions is used. It will ** initialize the driver. ** ****************************************************************************************/ static void LeafLightLibFuncInitializeLibrary(void) { /* Check function pointer and library handle. */ assert(leafLightLibFuncInitializeLibraryPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncInitializeLibraryPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ leafLightLibFuncInitializeLibraryPtr(); } } /*** end of LeafLightLibFuncInitializeLibrary ***/ /************************************************************************************//** ** \brief Frees allocated memory, unload the DLLs canlib32.dll has loaded and de- ** initializes data structures. ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncUnloadLibrary(void) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncUnloadLibraryPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncUnloadLibraryPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncUnloadLibraryPtr(); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncUnloadLibrary ***/ /************************************************************************************//** ** \brief Opens a CAN channel and returns a handle which is used in subsequent calls. ** \param channel The number of the channel. Channel numbering is hardware dependent. ** \param flags A combination of canOPEN_xxx flags. ** \return Handle (positive) to the channel if successful, canERR_xxx (negative) ** otherwise. ** ****************************************************************************************/ static CanHandle LeafLightLibFuncOpenChannel(int32_t channel, int32_t flags) { canHandle result = (canHandle)canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncOpenChannelPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncOpenChannelPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncOpenChannelPtr(channel, flags); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncOpenChannel ***/ /************************************************************************************//** ** \brief This function sets the nominal bus timing parameters for the specified CAN ** controller. The library provides default values for tseg1, tseg2, sjw and ** noSamp when freq is specified to one of the pre-defined constants, ** canBITRATE_xxx for classic CAN and canFD_BITRATE_xxx for CAN FD. ** \param hnd An open handle to a CAN controller. ** \param freq Bit rate (measured in bits per second); or one of the predefined ** constants (canBITRATE_xxx for classic CAN and canFD_BITRATE_xxx for ** CAN FD). ** \param tseg1 Time segment 1, that is, the number of quanta from (but not ** including) the Sync Segment to the sampling point. ** \param tseg2 Time segment 2, that is, the number of quanta from the sampling point ** to the end of the bit. ** \param sjw The Synchronization Jump Width. ** \param noSamp The number of sampling points; can be 1 or 3. ** \param syncmode Unsupported and ignored. ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncSetBusParams(const CanHandle hnd, int32_t freq, uint32_t tseg1, uint32_t tseg2, uint32_t sjw, uint32_t noSamp, uint32_t syncmode) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncSetBusParamsPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncSetBusParamsPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncSetBusParamsPtr(hnd, freq, tseg1, tseg2, sjw, noSamp, syncmode); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncSetBusParams ***/ /************************************************************************************//** ** \brief This function sets the driver type for a CAN controller. This corresponds ** loosely to the bus output control register in the CAN controller, hence the ** name of this function. CANLIB does not allow for direct manipulation of the ** bus output control register; instead, symbolic constants are used to select ** the desired driver type. ** \param hnd A handle to an open circuit. ** \param drivertype Can driver type (canDRIVER_xxx). ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncSetBusOutputControl(const CanHandle hnd, const uint32_t drivertype) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncSetBusOutputControlPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncSetBusOutputControlPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncSetBusOutputControlPtr(hnd, drivertype); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncSetBusOutputControl ***/ /************************************************************************************//** ** \brief This routine sets the message acceptance filters on a CAN channel. ** \param hnd A handle to an open circuit. ** \param code The acceptance code to set. ** \param mask The acceptance mask to set ** \param is_extended Select 29-bit CAN identifiers. ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncSetAcceptanceFilter(const CanHandle hnd, uint32_t code, uint32_t mask, int32_t is_extended) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncSetAcceptanceFilterPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncSetAcceptanceFilterPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncSetAcceptanceFilterPtr(hnd, code, mask, is_extended); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncSetAcceptanceFilter ***/ /************************************************************************************//** ** \brief This API call performs several different functions; these are described ** below. The functions are handle-specific unless otherwise noted; this means ** that they affect only the handle you pass to canIoCtl(), whereas other open ** handles will remain unaffected. The contents of buf after the call is ** dependent on the function code you specified. ** \param hnd A handle to an open circuit. ** \param func A canIOCTL_xxx function code. ** \param buf Pointer to a buffer containing function-dependent data; or a NULL ** pointer for certain function codes. The buffer can be used for both input ** and output depending on the function code. See canIOCTL_xxx. ** \param buflen The length of the buffer. ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncIoCtl(const CanHandle hnd, uint32_t func, void * buf, uint32_t buflen) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncIoCtlPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncIoCtlPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncIoCtlPtr(hnd, func, buf, buflen); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncIoCtl ***/ /************************************************************************************//** ** \brief Takes the specified channel on-bus. ** \param hnd An open handle to a CAN channel. ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncBusOn(const CanHandle hnd) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncBusOnPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncBusOnPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncBusOnPtr(hnd); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncBusOn ***/ /************************************************************************************//** ** \brief This function sends a CAN message. The call returns immediately after ** queuing the message to the driver. ** \param hnd A handle to an open CAN circuit. ** \param id The identifier of the CAN message to send. ** \param msg A pointer to the message data, or NULL. ** \param dlc The length of the message in bytes. ** \param flag A combination of message flags, canMSG_xxx (including canFDMSG_xxx if ** the CAN FD protocol is enabled). Use this parameter to send extended ** (29-bit) frames and/or remote frames. Use canMSG_EXT and/or canMSG_RTR for ** this purpose. ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncWrite(const CanHandle hnd, int32_t id, void * msg, uint32_t dlc, uint32_t flag) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncWritePtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncWritePtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncWritePtr(hnd, id, msg, dlc, flag); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncWrite ***/ /************************************************************************************//** ** \brief Reads a message from the receive buffer. If no message is available, the ** function returns immediately with return code canERR_NOMSG. ** \param hnd A handle to an open circuit. ** \param id Pointer to a buffer which receives the CAN identifier. This buffer will ** only get the identifier. To determine whether this identifier was standard ** (11-bit) or extended (29-bit), and/or whether it was remote or not, or if ** it was an error frame, examine the contents of the flag argument. ** \param msg Pointer to the buffer which receives the message data. This buffer must ** be large enough (i.e. 8 bytes.) Only the message data is copied; the rest ** of the buffer is left as-is. ** \param dlc Pointer to a buffer which receives the message length. ** \param flag Pointer to a buffer which receives the message flags, which is a ** combination of the canMSG_xxx and canMSGERR_xxx values. ** \param time Pointer to a buffer which receives the message time stamp. ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncRead(const CanHandle hnd, int32_t * id, void * msg, uint32_t * dlc, uint32_t * flag, uint32_t * time) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncReadPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncReadPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncReadPtr(hnd, id, msg, dlc, flag, time); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncRead ***/ /************************************************************************************//** ** \brief Returns the status for the specified circuit. flags points to a longword ** which receives a combination of the canSTAT_xxx flags. ** \param hnd A handle to an open circuit. ** \param flags Pointer to a DWORD which receives the status flags; this is a ** combination of any of the canSTAT_xxx. ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncReadStatus(const CanHandle hnd, uint32_t * const flags) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncReadStatusPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncReadStatusPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncReadStatusPtr(hnd, flags); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncReadStatus ***/ /************************************************************************************//** ** \brief Takes the specified channel off-bus. ** \param hnd A handle to an open circuit. ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncBusOff(const CanHandle hnd) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncBusOffPtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncBusOffPtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncBusOffPtr(hnd); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncBusOff ***/ /************************************************************************************//** ** \brief Closes the channel associated with the handle. If no other threads are ** using the CAN circuit, it is taken off bus. The handle can not be used for ** further references to the channel, so any variable containing it should be ** zeroed. ** \param hnd A handle to an open circuit. ** \return canOK if successful, canERR_xxx otherwise. ** ****************************************************************************************/ static canStatus LeafLightLibFuncClose(const CanHandle hnd) { canStatus result = canERR_NOTINITIALIZED; /* Check function pointer and library handle. */ assert(leafLightLibFuncClosePtr != NULL); assert(leafLightDllHandle != NULL); /* Only continue with valid function pointer and library handle. */ if ((leafLightLibFuncClosePtr != NULL) && (leafLightDllHandle != NULL)) /*lint !e774 */ { /* Call library function. */ result = leafLightLibFuncClosePtr(hnd); } /* Give the result back to the caller. */ return result; } /*** end of LeafLightLibFuncClose ***/ /*********************************** end of leaflight.c ********************************/