openblt/Host/Source/LibOpenBLT/port/windows/canif/kvaser/leaflight.c

1293 lines
52 KiB
C

/************************************************************************************//**
* \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 <assert.h> /* for assertions */
#include <stdint.h> /* for standard integer types */
#include <stddef.h> /* for NULL declaration */
#include <stdbool.h> /* for boolean type */
#include <stdlib.h> /* for standard library */
#include <string.h> /* for string library */
#include "candriver.h" /* Generic CAN driver module */
#include "leaflight.h" /* Kvaser Leaf Light v2 interface */
#include <windows.h> /* 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 ********************************/