From f21ff722f8b67d37cecc31fd2f65964811f5ac58 Mon Sep 17 00:00:00 2001 From: Frank Voorburg Date: Thu, 24 Aug 2017 07:54:12 +0000 Subject: [PATCH] Refs #316. Implemented empty framework for the Lawicel CANUSB interface. git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@353 5dc33758-31d5-4daf-9ae8-b24bf3d40d73 --- Host/Source/LibOpenBLT/candriver.c | 5 + .../port/windows/canif/lawicel/canusb.c | 387 ++++++++++++++++++ .../port/windows/canif/lawicel/canusb.h | 53 +++ .../port/windows/canif/lawicel/lawicel_can.h | 357 ++++++++++++++++ Host/libopenblt.dll | Bin 130048 -> 134144 bytes 5 files changed, 802 insertions(+) create mode 100644 Host/Source/LibOpenBLT/port/windows/canif/lawicel/canusb.c create mode 100644 Host/Source/LibOpenBLT/port/windows/canif/lawicel/canusb.h create mode 100644 Host/Source/LibOpenBLT/port/windows/canif/lawicel/lawicel_can.h diff --git a/Host/Source/LibOpenBLT/candriver.c b/Host/Source/LibOpenBLT/candriver.c index 39bef7dc..324c8354 100644 --- a/Host/Source/LibOpenBLT/candriver.c +++ b/Host/Source/LibOpenBLT/candriver.c @@ -38,6 +38,7 @@ #if defined(PLATFORM_WIN32) #include "pcanusb.h" /* Peak PCAN-USB interface */ #include "leaflight.h" /* Kvaser Leaf Light v2 interface */ +#include "canusb.h" /* Lawicel CANUSB interface */ #endif #if defined(PLATFORM_LINUX) #include "socketcan.h" /* SocketCAN interface */ @@ -89,6 +90,10 @@ void CanInit(tCanSettings const * settings) { canIfPtr = LeafLightGetInterface(); } + else if (strcmp(settings->devicename, "lawicel_canusb") == 0) + { + canIfPtr = CanUsbGetInterface(); + } #endif #if defined(PLATFORM_LINUX) /* On Linux, the device name is the name of the SocketCAN link, so always link diff --git a/Host/Source/LibOpenBLT/port/windows/canif/lawicel/canusb.c b/Host/Source/LibOpenBLT/port/windows/canif/lawicel/canusb.c new file mode 100644 index 00000000..ecd04901 --- /dev/null +++ b/Host/Source/LibOpenBLT/port/windows/canif/lawicel/canusb.c @@ -0,0 +1,387 @@ +/************************************************************************************//** +* \file canusb.c +* \brief Lawicel CANUSB interface source file. +* \ingroup Lawicel_CanUsb +* \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 "canusb.h" /* Lawicel CANUSB interface */ +#include /* for Windows API */ +#include "lawicel_can.h" /* for Lawicel CANUSB API */ + + +/*************************************************************************************** +* Function prototypes +****************************************************************************************/ +/* CAN interface functions. */ +static void CanUsbInit(tCanSettings const * settings); +static void CanUsbTerminate(void); +static bool CanUsbConnect(void); +static void CanUsbDisconnect(void); +static bool CanUsbTransmit(tCanMsg const * msg); +static bool CanUsbIsBusError(void); +static void CanUsbRegisterEvents(tCanEvents const * events); +/* CAN message reception thread. */ +static DWORD WINAPI CanUsbReceptionThread(LPVOID pv); + + +/**************************************************************************************** +* Local constant declarations +****************************************************************************************/ +/** \brief CAN interface structure filled with Lawicel CANUSB specifics. */ +static const tCanInterface canUsbInterface = +{ + CanUsbInit, + CanUsbTerminate, + CanUsbConnect, + CanUsbDisconnect, + CanUsbTransmit, + CanUsbIsBusError, + CanUsbRegisterEvents +}; + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief The settings to use in this CAN interface. */ +static tCanSettings canUsbSettings; + +/** \brief List with callback functions that this driver should use. */ +static tCanEvents * canUsbEventsList; + +/** \brief Total number of event entries into the \ref canUsbEventsList list. */ +static uint32_t canUsbEventsEntries; + +/** \brief Handle for the event to terminate the reception thread. */ +static HANDLE canUsbTerminateEvent; + +/** \brief Handle for the CAN reception thread. */ +static HANDLE canUsbRxThreadHandle; + + +/***********************************************************************************//** +** \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 * CanUsbGetInterface(void) +{ + return &canUsbInterface; +} /*** end of CanUsbGetInterface ***/ + + +/************************************************************************************//** +** \brief Initializes the CAN interface. +** \param settings Pointer to the CAN interface settings. +** +****************************************************************************************/ +static void CanUsbInit(tCanSettings const * settings) +{ + char * canDeviceName; + + /* Initialize locals. */ + canUsbEventsList = NULL; + canUsbEventsEntries = 0; + canUsbTerminateEvent = NULL; + canUsbRxThreadHandle = NULL; + /* Reset CAN interface settings. */ + canUsbSettings.devicename = ""; + canUsbSettings.channel = 0; + canUsbSettings.baudrate = CAN_BR500K; + canUsbSettings.code = 0x00000000u; + canUsbSettings.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. */ + canUsbSettings = *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); + canUsbSettings.devicename = canDeviceName; + } + } + /* ##Vg TODO Perform initialization of Lawicel CANUSB API. */ + } +} /*** end of CanUsbInit ***/ + + +/************************************************************************************//** +** \brief Terminates the CAN interface. +** +****************************************************************************************/ +static void CanUsbTerminate(void) +{ + /* ##Vg TODO Perform termination of Lawicel CANUSB API. */ + /* Release memory that was allocated for storing the device name. */ + if (canUsbSettings.devicename != NULL) + { + free((char *)canUsbSettings.devicename); + } + /* Reset CAN interface settings. */ + canUsbSettings.devicename = ""; + canUsbSettings.channel = 0; + canUsbSettings.baudrate = CAN_BR500K; + canUsbSettings.code = 0x00000000u; + canUsbSettings.mask = 0x00000000u; + /* Release memory that was allocated for CAN events and reset the entry count. */ + if ( (canUsbEventsList != NULL) && (canUsbEventsEntries != 0) ) + { + free(canUsbEventsList); + canUsbEventsEntries = 0; + } +} /*** end of CanUsbTerminate ***/ + + +/************************************************************************************//** +** \brief Connects the CAN interface. +** \return True if connected, false otherwise. +** +****************************************************************************************/ +static bool CanUsbConnect(void) +{ + bool result = false; + bool baudrateSupported = true; + + /* 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. */ + canUsbTerminateEvent = NULL; + canUsbRxThreadHandle = NULL; + + /* Only continue with valid settings. */ + if (baudrateSupported) + { + /* Init result code to success and only negate it on detection of error. */ + result = true; + + /* ##Vg TODO Process and verify settings, configure acceptance filter, connect. */ + result = false; /* Temporary. */ + + /* Create the terminate event handle used in the reception thread. */ + if (result) + { + canUsbTerminateEvent = CreateEvent(NULL, TRUE, FALSE, ""); + if (canUsbTerminateEvent == NULL) + { + result = false; + } + } + /* Start the reception thread as the last step. */ + if (result) + { + canUsbRxThreadHandle = CreateThread(NULL, 0, CanUsbReceptionThread, + NULL, 0, NULL); + if (canUsbRxThreadHandle == NULL) + { + result = false; + } + } + } + + /* Clean-up in case an error occurred. */ + if (!result) + { + if (canUsbTerminateEvent != NULL) + { + /* Close the event handle. */ + (void)CloseHandle(canUsbTerminateEvent); + canUsbTerminateEvent = NULL; + } + } + /* Give the result back to the caller. */ + return result; +} /*** end of CanUsbConnect ***/ + + +/************************************************************************************//** +** \brief Disconnects the CAN interface. +** +****************************************************************************************/ +static void CanUsbDisconnect(void) +{ + /* Stop the reception thread. */ + if (canUsbRxThreadHandle != NULL) + { + /* Trigger event to request the reception thread to stop. */ + (void)SetEvent(canUsbTerminateEvent); + /* Wait for the thread to signal termination. */ + (void)WaitForSingleObject(canUsbRxThreadHandle, INFINITE); + /* Close the thread handle. */ + (void)CloseHandle(canUsbRxThreadHandle); + canUsbRxThreadHandle = NULL; + } + /* Close the terminate event handle. */ + if (canUsbTerminateEvent != NULL) + { + (void)CloseHandle(canUsbTerminateEvent); + canUsbTerminateEvent = NULL; + } + /* ##Vg TODO Go off the bus and close the channel. */ +} /*** end of CanUsbDisconnect ***/ + + +/************************************************************************************//** +** \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 CanUsbTransmit(tCanMsg const * msg) +{ + bool result = false; + + /* Check parameters. */ + assert(msg != NULL); + + /* Only continue with valid parameters. */ + if (msg != NULL) /*lint !e774 */ + { + /* ##Vg TODO Transmit and trigger event(s). */ + } + /* Give the result back to the caller. */ + return result; +} /*** end of CanUsbTransmit ***/ + + +/************************************************************************************//** +** \brief Checks if a bus off or bus heavy situation occurred. +** \return True if a bus error situation was detected, false otherwise. +** +****************************************************************************************/ +static bool CanUsbIsBusError(void) +{ + bool result = false; + + /* ##Vg TODO Check and process status. */ + + /* Give the result back to the caller. */ + return result; +} /*** end of CanUsbIsBusError ***/ + + +/************************************************************************************//** +** \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 CanUsbRegisterEvents(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. + */ + canUsbEventsList = realloc(canUsbEventsList, + (sizeof(tCanEvents) * (canUsbEventsEntries + 1))); + /* Assert reallocation. */ + assert(canUsbEventsList != NULL); + /* Only continue if reallocation was successful. */ + if (canUsbEventsList != NULL) + { + /* Increment events entry count. */ + canUsbEventsEntries++; + /* Store the events in the new entry. */ + canUsbEventsList[canUsbEventsEntries - 1] = *events; + } + /* Reallocation failed. */ + else + { + /* Reset events entry count. */ + canUsbEventsEntries = 0; + } + } +} /*** end of CanUsbRegisterEvents ***/ + + +/************************************************************************************//** +** \brief CAN message reception thread. +** \param pv Pointer to thread parameters. +** \return Thread exit code. +** +****************************************************************************************/ +static DWORD WINAPI CanUsbReceptionThread(LPVOID pv) +{ + DWORD waitResult; + bool running = true; + + /* Parameter not used. */ + (void)pv; + + /* Enter thread's infinite loop. */ + while (running) + { + waitResult = WaitForSingleObject(canUsbTerminateEvent, 10); + switch (waitResult) + { + /* Termination event. */ + case WAIT_OBJECT_0 + 0: /*lint !e835 */ + /* Stop thread. */ + running = false; + break; + default: + break; + } + } + /* Exit thread. */ + return 0; +} /*** end of CanUsbReceptionThread ***/ + + +/*********************************** end of canusb.c ***********************************/ + diff --git a/Host/Source/LibOpenBLT/port/windows/canif/lawicel/canusb.h b/Host/Source/LibOpenBLT/port/windows/canif/lawicel/canusb.h new file mode 100644 index 00000000..6c13ddd1 --- /dev/null +++ b/Host/Source/LibOpenBLT/port/windows/canif/lawicel/canusb.h @@ -0,0 +1,53 @@ +/************************************************************************************//** +* \file canusb.h +* \brief Lawicel CANUSB interface header file. +* \ingroup Lawicel_CanUsb +* \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 +****************************************************************************************/ +/************************************************************************************//** +* \defgroup Lawicel_CanUsb Lawicel CANUSB interface +* \brief This module implements the CAN interface for the Lawicel CANUSB. When using +* the Lawicel CANUSB interface, the 32-bit driver for the CANUSB DLL API +* should be installed: +* http://www.can232.com/download/canusb_setup_win32_v_2_2.zip +* \ingroup CanDriver +****************************************************************************************/ +#ifndef CANUSB_H +#define CANUSB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************************** +* Function prototypes +****************************************************************************************/ +tCanInterface const * CanUsbGetInterface(void); + +#ifdef __cplusplus +} +#endif + +#endif /* CANUSB_H */ +/*********************************** end of canusb.h ***********************************/ diff --git a/Host/Source/LibOpenBLT/port/windows/canif/lawicel/lawicel_can.h b/Host/Source/LibOpenBLT/port/windows/canif/lawicel/lawicel_can.h new file mode 100644 index 00000000..8aeb1cb5 --- /dev/null +++ b/Host/Source/LibOpenBLT/port/windows/canif/lawicel/lawicel_can.h @@ -0,0 +1,357 @@ +/* +** __ ___ ____ __ ____ __ ______ _______ __ +** | | / \ \ \ / \ / / | | / || ____|| | +** | | / ^ \ \ \/ \/ / | | | ,----'| |__ | | +** | | / /_\ \ \ / | | | | | __| | | +** | `----./ _____ \ \ /\ / | | | `----.| |____ | `----. +** |_______/__/ \__\ \__/ \__/ |__| \______||_______||_______| +** +** Copyright (c) 2005-2012 LAWICEL AB, Sweden +*/ + +#ifndef __LAWICELCANH__ +#define __LAWICELCANH__ + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +// Types +typedef unsigned char _u8; +typedef unsigned __int16 _u16; +typedef unsigned __int32 _u32; + + +typedef long CANHANDLE; +typedef unsigned char CANDATA; + +// Status bits +#define CANSTATUS_RECEIVE_FIFO_FULL 0x01 +#define CANSTATUS_TRANSMIT_FIFO_FULL 0x02 +#define CANSTATUS_ERROR_WARNING 0x04 +#define CANSTATUS_DATA_OVERRUN 0x08 +#define CANSTATUS_ERROR_PASSIVE 0x20 +#define CANSTATUS_ARBITRATION_LOST 0x40 +#define CANSTATUS_BUS_ERROR 0x80 + +// Filter mask settings +#define CANUSB_ACCEPTANCE_CODE_ALL 0x00000000 +#define CANUSB_ACCEPTANCE_MASK_ALL 0xFFFFFFFF + +// Message flags +#define CANMSG_EXTENDED 0x80 // Extended CAN id +#define CANMSG_RTR 0x40 // Remote frame + +// Flush flags +#define FLUSH_WAIT 0x00 +#define FLUSH_DONTWAIT 0x01 +#define FLUSH_EMPTY_INQUEUE 0x02 + +// CAN Frame +typedef struct { + _u32 id; // Message id + _u32 timestamp; // timestamp in milliseconds + _u8 flags; // [extended_id|1][RTR:1][reserver:6] + _u8 len; // Frame size (0.8) + _u8 data[ 8 ]; // Databytes 0..7 +} CANMsg; + + +// Alternative CAN Frame +typedef struct { + _u32 id; // Message id + _u32 timestamp; // timestamp in milliseconds + _u8 flags; // [extended_id|1][RTR:1][reserver:6] + _u8 len; // Frame size (0.8) +} CANMsgEx; + +// Interface statistics +typedef struct structCANUsbStatistics { + _u32 cntReceiveFrames; // # of receive frames + _u32 cntTransmitFrames; // # of transmitted frames + _u32 cntReceiveData; // # of received data bytes + _u32 cntTransmitData; // # of transmitted data bytes + _u32 cntOverruns; // # of overruns + _u32 cntBusWarnings; // # of bys warnings + _u32 cntBusOff; // # of bus off's +} CANUsbStatistics; + + +// Error return codes +#define ERROR_CANUSB_OK 1 +#define ERROR_CANUSB_GENERAL -1 +#define ERROR_CANUSB_OPEN_SUBSYSTEM -2 +#define ERROR_CANUSB_COMMAND_SUBSYSTEM -3 +#define ERROR_CANUSB_NOT_OPEN -4 +#define ERROR_CANUSB_TX_FIFO_FULL -5 +#define ERROR_CANUSB_INVALID_PARAM -6 +#define ERROR_CANUSB_NO_MESSAGE -7 +#define ERROR_CANUSB_MEMORY_ERROR -8 +#define ERROR_CANUSB_NO_DEVICE -9 +#define ERROR_CANUSB_TIMEOUT -10 +#define ERROR_CANUSB_INVALID_HARDWARE -11 + + +// Open flags +#define CANUSB_FLAG_TIMESTAMP 0x0001 // Timestamp messages +#define CANUSB_FLAG_QUEUE_REPLACE 0x0002 // If input queue is full remove + // oldest message and insert new + // message. +#define CANUSB_FLAG_BLOCK 0x0004 // Block receive/transmit +#define CANUSB_FLAG_SLOW 0x0008 // Check ACK/NACK's +#define CANUSB_FLAG_NO_LOCAL_SEND 0x0010 // Don't send transmited frames on + // other local channels for the same + // interface + + + +// This is the define for the received callback method +typedef void ( __stdcall * LPFNDLL_RECEIVE_CALLBACK) ( CANMsg *pMsg ); + + + +// Prototypes + +/////////////////////////////////////////////////////////////////////////////// +// canusb_Open +// +// Open CAN interface to device +// +// Returs handle to device if open was successfull or zero +// or negative error code on falure. +// +// +// szID +// ==== +// Serial number for adapter or NULL to open the first found. +// +// +// szBitrate +// ========= +// "10" for 10kbps +// "20" for 20kbps +// "50" for 50kbps +// "100" for 100kbps +// "250" for 250kbps +// "500" for 500kbps +// "800" for 800kbps +// "1000" for 1Mbps +// +// or +// +// btr0:btr1 pair ex. "0x03:0x1c" or 3:28 +// +// acceptance_code +// =============== +// Set to CANUSB_ACCEPTANCE_CODE_ALL to get all messages. +// +// acceptance_mask +// =============== +// Set to CANUSB_ACCEPTANCE_MASk_ALL to get all messages. +// +// flags +// ===== +// CANUSB_FLAG_TIMESTAMP - Timestamp will be set by adapter. + +CANHANDLE WINAPI canusb_Open( LPCSTR szID, + LPCSTR szBitrate, + _u32 acceptance_code, + _u32 acceptance_mask, + _u32 flags ); + + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_Close +// +// Close channel with handle h. +// +// Returns <= 0 on failure. >0 on success. + +int WINAPI canusb_Close( CANHANDLE h ); + + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_Read +// +// Read message from channel with handle h. +// +// Returns <= 0 on failure. >0 on success. +// + +int WINAPI canusb_Read( CANHANDLE h, CANMsg *msg ); + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_ReadEx +// +// Read message from channel with handle h. +// +// This is a version without a data-array in the structure to work with LabView +// +// Returns <= 0 on failure. >0 on success. +// + +int WINAPI canusb_ReadEx( CANHANDLE h, CANMsgEx *msg, CANDATA *pData ); + +/////////////////////////////////////////////////////////////////////////////// +// canusb_ReadFirst +// +// Read message from channel with handle h and id "id" which satisfy flags. +// +// Returns <= 0 on failure. >0 on success. +// + +int WINAPI canusb_ReadFirst( CANHANDLE h, + _u32 id, + _u32 flags, + CANMsg *msg ); + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_ReadFirstEx +// +// Read message from channel with handle h and id "id" which satisfying flags. +// +// This is a version without a data-array in the structure to work with LabView +// +// Returns <= 0 on failure. >0 on success. +// + +int WINAPI canusb_ReadFirstEx( CANHANDLE h, + _u32 id, + _u32 flags, + CANMsgEx *msg, + CANDATA *pData ); + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_Write +// +// Write message to channel with handle h. +// +// Returns <= 0 on failure. >0 on success. +// + +int WINAPI canusb_Write( CANHANDLE h, CANMsg *msg ); + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_WriteEx +// +// Write message to channel with handle h. +// +// This is a version without a data-array in the structure to work with LabView +// +// Returns <= 0 on failure. >0 on success. +// + +int WINAPI canusb_WriteEx( CANHANDLE h, CANMsgEx *msg, CANDATA *pData ); + + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_Status +// +// Get Adaper status for channel with handle h. + +int WINAPI canusb_Status( CANHANDLE h ); + + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_VersionInfo +// +// Get hardware/fi4rmware and driver version for channel with handle h. +// +// Returns <= 0 on failure. >0 on success. +// +// + +int WINAPI canusb_VersionInfo( CANHANDLE h, LPSTR verinfo ); + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_Flush +// +// Flush output buffer on channel with handle h. +// +// Returns <= 0 on failure. >0 on success. +// +// If flushflags is set to FLUSH_DONTWAIT the queue is just emptied and +// there will be no wait for any frames in it to be sent +// + +int WINAPI canusb_Flush( CANHANDLE h, _u8 flushflags ); + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_GetStatistics +// +// Get transmission statistics for channel with handle h. +// +// Returns <= 0 on failure. >0 on success. +// +// + +int WINAPI canusb_GetStatistics( CANHANDLE h, CANUsbStatistics *pStatistics ); + +/////////////////////////////////////////////////////////////////////////////// +// canusb_SetTimeouts +// +// Set timeouts used for blocking calls for channel with handle h. +// +// Returns <= 0 on failure. >0 on success. +// +// + +int WINAPI canusb_SetTimeouts( CANHANDLE h, + _u32 receiveTimeout, + _u32 transmitTimeout ); + +/////////////////////////////////////////////////////////////////////////////// +// canusb_getFirstAdapter +// +// Get the first found adapter that is connected to this machine. +// +// Returns <= 0 on failure. 0 if no adapter found. >0 if one or more adapters +// is found. +// +// + +int WINAPI canusb_getFirstAdapter( char *szAdapter, int size ); + + +/////////////////////////////////////////////////////////////////////////////// +// canusb_getNextAdapter +// +// Get the found adapter(s) in turn that is connected to this machine. +// +// Returns <= 0 on failure. >0 for a valid adapter return. +// +// + +int WINAPI canusb_getNextAdapter( char *szAdapter, int size ); + +/////////////////////////////////////////////////////////////////////////////// +// canusb_setReceiveCallBack +// +// Set a receive call back function. Set the callback to NULL to +// reset it. +// +// Returns <= 0 on failure. >0 for a valid adapter return. +// +// + +int WINAPI canusb_setReceiveCallBack( CANHANDLE handle, + LPFNDLL_RECEIVE_CALLBACK fn ); + + +#ifdef __cplusplus +} +#endif + +#endif // __LAWICELCANH__ diff --git a/Host/libopenblt.dll b/Host/libopenblt.dll index c93732f569f6482098337310cf41b2a99b8f212f..e38715d9bbe73d3a187814e495d31f8e75f5025d 100644 GIT binary patch delta 29700 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 z

PojxEamiDAK)h}n0a&ZTwUJXX7v0 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 I>{t2!0yc%~>i_@%