diff --git a/Host/Source/LibOpenBLT/CMakeLists.txt b/Host/Source/LibOpenBLT/CMakeLists.txt index da0a62a5..42f36f10 100644 --- a/Host/Source/LibOpenBLT/CMakeLists.txt +++ b/Host/Source/LibOpenBLT/CMakeLists.txt @@ -66,7 +66,7 @@ if(WIN32) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_WIN32 -D_CRT_SECURE_NO_WARNINGS") elseif(UNIX) set(PROJECT_PORT_DIR ${PROJECT_SOURCE_DIR}/port/linux) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_LINUX") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_LINUX -pthread") endif(WIN32) # Set the output directory diff --git a/Host/Source/LibOpenBLT/port/linux/critutil.c b/Host/Source/LibOpenBLT/port/linux/critutil.c new file mode 100644 index 00000000..a0b67609 --- /dev/null +++ b/Host/Source/LibOpenBLT/port/linux/critutil.c @@ -0,0 +1,64 @@ +/************************************************************************************//** +* \file port/linux/critutil.c +* \brief Critical section utility source file. +* \ingroup Utility +* \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 standard integer types */ +#include /* for boolean type */ +#include /* for posix threads */ +#include "util.h" /* Utility module */ + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ + + +/************************************************************************************//** +** \brief Enters a critical section. The functions UtilCriticalSectionEnter and +** UtilCriticalSectionExit should always be used in a pair. +** +****************************************************************************************/ +void UtilCriticalSectionEnter(void) +{ +} /*** end of UtilCriticalSectionEnter ***/ + + +/************************************************************************************//** +** \brief Leaves a critical section. The functions UtilCriticalSectionEnter and +** UtilCriticalSectionExit should always be used in a pair. +** +****************************************************************************************/ +void UtilCriticalSectionExit(void) +{ +} /*** end of UtilCriticalSectionExit ***/ + + +/*********************************** end of critutil.c *********************************/ + diff --git a/Host/Source/LibOpenBLT/port/windows/critutil.c b/Host/Source/LibOpenBLT/port/windows/critutil.c new file mode 100644 index 00000000..7b57ba12 --- /dev/null +++ b/Host/Source/LibOpenBLT/port/windows/critutil.c @@ -0,0 +1,151 @@ +/************************************************************************************//** +* \file port/windows/critutil.c +* \brief Critical section utility source file. +* \ingroup Utility +* \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 boolean type */ +#include /* for windows library */ +#include "util.h" /* Utility module */ + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Flag to determine if the critical section object was already initialized. */ +static volatile bool criticalSectionInitialized = false; + +/** \brief Crital section nesting counter. ***/ +static volatile uint32_t criticalSectionNesting; + +/** \brief Critical section object. */ +static volatile CRITICAL_SECTION criticalSection; + + +/************************************************************************************//** +** \brief Initializes the critical section module. Should be called before the +** Enter/Exit functions are used. It is okay to call this initialization +** multiple times from different modules. +** +****************************************************************************************/ +void UtilCriticalSectionInit(void) +{ + /* Only initialize if not yet done so previously. */ + if (!criticalSectionInitialized) + { + /* Initialize the critical section object. */ + InitializeCriticalSection(&criticalSection); + /* Reset nesting counter. */ + criticalSectionNesting = 0; + /* Set initialized flag. */ + criticalSectionInitialized = true; + } +} /*** end of UtilCriticalSectionInit ***/ + + +/************************************************************************************//** +** \brief Terminates the critical section module. Should be called once critical +** sections are no longer needed. Typically called from another module's +** termination function that also initialized it. It is okay to call this +** termination multiple times from different modules. +** +****************************************************************************************/ +void UtilCriticalSectionTerminate(void) +{ + /* Only terminate if it was initialized. */ + if (criticalSectionInitialized) + { + /* Reset the initialized flag. */ + criticalSectionInitialized = false; + /* Reset nesting counter. */ + criticalSectionNesting = 0; + /* Delete the critical section object. */ + DeleteCriticalSection(&criticalSection); + } +} /*** end of UtilCriticalSectionTerminate ***/ + + + +/************************************************************************************//** +** \brief Enters a critical section. The functions UtilCriticalSectionEnter and +** UtilCriticalSectionExit should always be used in a pair. +** +****************************************************************************************/ +void UtilCriticalSectionEnter(void) +{ + /* Check initialization. */ + assert(criticalSectionInitialized); + + /* Only continue if actually initialized. */ + if (criticalSectionInitialized) + { + /* Enter the critical section if not already entered. */ + if (criticalSectionNesting == 0) + { + EnterCriticalSection(&criticalSection); + } + /* Increment nesting counter. */ + criticalSectionNesting++; + } +} /*** end of UtilCriticalSectionEnter ***/ + + +/************************************************************************************//** +** \brief Leaves a critical section. The functions UtilCriticalSectionEnter and +** UtilCriticalSectionExit should always be used in a pair. +** +****************************************************************************************/ +void UtilCriticalSectionExit(void) +{ + /* Check initialization. */ + assert(criticalSectionInitialized); + + /* Only continue if actually initialized. */ + if (criticalSectionInitialized) + { + /* Sanity check. */ + assert(criticalSectionNesting > 0); + + /* Decrement nesting counter if it is valid. */ + if (criticalSectionNesting > 0) + { + criticalSectionNesting--; + /* Leave the critical section. */ + if (criticalSectionNesting == 0) + { + LeaveCriticalSection(&criticalSection); + } + } + } +} /*** end of UtilCriticalSectionExit ***/ + + +/*********************************** end of critutil.c *********************************/ + diff --git a/Host/Source/LibOpenBLT/util.h b/Host/Source/LibOpenBLT/util.h index 4d538fbc..56ffb062 100644 --- a/Host/Source/LibOpenBLT/util.h +++ b/Host/Source/LibOpenBLT/util.h @@ -49,6 +49,10 @@ uint32_t UtilChecksumCrc32Calculate(uint8_t const * data, uint32_t len); bool UtilFileExtractFilename(char const * fullFilename, char * filenameBuffer); uint32_t UtilTimeGetSystemTimeMs(void); void UtilTimeDelayMs(uint16_t delay); +void UtilCriticalSectionInit(void); +void UtilCriticalSectionTerminate(void); +void UtilCriticalSectionEnter(void); +void UtilCriticalSectionExit(void); #ifdef __cplusplus diff --git a/Host/Source/LibOpenBLT/xcploader.c b/Host/Source/LibOpenBLT/xcploader.c index c630c4fc..35c28f25 100644 --- a/Host/Source/LibOpenBLT/xcploader.c +++ b/Host/Source/LibOpenBLT/xcploader.c @@ -237,16 +237,16 @@ static bool XcpLoaderStart(void) break; } } - } - /* Check if a connection with the target could be made within the finite amount - * of retries. - */ - if (!xcpConnected) - { - /* Disconnect the transport layer again. */ - xcpSettings.transport->Disconnect(); - /* Update the result. */ - result = false; + /* Check if a connection with the target could be made within the finite amount + * of retries. + */ + if (!xcpConnected) + { + /* Disconnect the transport layer again. */ + xcpSettings.transport->Disconnect(); + /* Update the result. */ + result = false; + } } /* Place the target in programming mode if connected. */ diff --git a/Host/Source/LibOpenBLT/xcptpcan.c b/Host/Source/LibOpenBLT/xcptpcan.c index 69e94ed2..0a042cd2 100644 --- a/Host/Source/LibOpenBLT/xcptpcan.c +++ b/Host/Source/LibOpenBLT/xcptpcan.c @@ -48,12 +48,16 @@ /**************************************************************************************** * Function prototypes ****************************************************************************************/ +/* Transport layer module functions. */ static void XcpTpCanInit(void const * settings); static void XcpTpCanTerminate(void); static bool XcpTpCanConnect(void); static void XcpTpCanDisconnect(void); static bool XcpTpCanSendPacket(tXcpTransportPacket const * txPacket, tXcpTransportPacket * rxPacket, uint16_t timeout); +/* CAN event functions. */ +static void XcpTpCanEventMessageTransmitted(tCanMsg const * msg); +static void XcpTpCanEventMessageReceived(tCanMsg const * msg); /**************************************************************************************** @@ -69,6 +73,20 @@ static const tXcpTransport canTransport = XcpTpCanSendPacket }; +/** \brief CAN driver event functions. */ +static const tCanEvents canEvents = +{ + XcpTpCanEventMessageTransmitted, + XcpTpCanEventMessageReceived +}; + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief The settings to use in this transport layer. */ +static tXcpTpCanSettings tpCanSettings; + /***********************************************************************************//** ** \brief Obtains a pointer to the transport layer structure, so that it can be @@ -90,15 +108,103 @@ tXcpTransport const * XcpTpCanGetTransport(void) ****************************************************************************************/ static void XcpTpCanInit(void const * settings) { + char * canDeviceName; + tCanInterface const * canInterface = NULL; + tCanSettings canSettings; + + /* Reset transport layer settings. */ + tpCanSettings.device = NULL; + tpCanSettings.channel = 0; + tpCanSettings.baudrate = 500000; + tpCanSettings.transmitId = 0x667; + tpCanSettings.receiveId = 0x7e1; + tpCanSettings.useExtended = false; + + /* This module uses critical sections so initialize them. */ + UtilCriticalSectionInit(); + /* Check parameters. */ assert(settings != NULL); /* Only continue with valid parameters. */ if (settings != NULL) /*lint !e774 */ { - /* ##Vg TODO Extract and set the pointer to the CAN interface to link. */ + /* Shallow copy the transport layer settings for layer usage. */ + tpCanSettings = *((tXcpTpCanSettings *)settings); + /* The device name 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(((tXcpTpCanSettings *)settings)->device != NULL); + if (((tXcpTpCanSettings *)settings)->device != NULL) /*lint !e774 */ + { + canDeviceName = malloc(strlen(((tXcpTpCanSettings *)settings)->device) + 1); + assert(canDeviceName != NULL); + if (canDeviceName != NULL) /*lint !e774 */ + { + strcpy(canDeviceName, ((tXcpTpCanSettings *)settings)->device); + tpCanSettings.device = canDeviceName; + + /* Determine the pointer to the correct CAN interface, based on the specified + * device name. + */ +#if defined(PLATFORM_WIN32) + if (strcmp(tpCanSettings.device, "peak_pcanusb") == 0) + { + canInterface = PCanUsbGetInterface(); + } +#endif + } + } } - /* ##Vg TODO Implement CAN module initialization. */ + + /* Convert the transport layer settings to CAN driver settings. */ + canSettings.devicename = tpCanSettings.device; + canSettings.channel = tpCanSettings.channel; + switch (tpCanSettings.baudrate) + { + case 1000000: + canSettings.baudrate = CAN_BR1M; + break; + case 800000: + canSettings.baudrate = CAN_BR800K; + break; + case 500000: + canSettings.baudrate = CAN_BR500K; + break; + case 250000: + canSettings.baudrate = CAN_BR250K; + break; + case 125000: + canSettings.baudrate = CAN_BR125K; + break; + case 100000: + canSettings.baudrate = CAN_BR100K; + break; + case 50000: + canSettings.baudrate = CAN_BR50K; + break; + case 20000: + canSettings.baudrate = CAN_BR20K; + break; + case 10000: + canSettings.baudrate = CAN_BR10K; + break; + default: + /* Default to 500 kbits/sec in case an unsupported baudrate was specified. */ + canSettings.baudrate = CAN_BR500K; + break; + } + /* Configure the reception acceptance filter to receive only one CAN identifier. */ + canSettings.code = tpCanSettings.receiveId; + if (tpCanSettings.useExtended) + { + canSettings.code |= CAN_MSG_EXT_ID_MASK; + } + canSettings.mask = 0x9fffffff; + /* Initialize the CAN driver. */ + CanInit(&canSettings, canInterface); + /* Register CAN event functions. */ + CanRegisterEvents(&canEvents); } /*** end of XcpTpCanInit ***/ @@ -108,7 +214,22 @@ static void XcpTpCanInit(void const * settings) ****************************************************************************************/ static void XcpTpCanTerminate(void) { - /* ##Vg TODO Implement. */ + /* Terminate the CAN driver. */ + CanTerminate(); + /* Release memory that was allocated for storing the device name. */ + if (tpCanSettings.device != NULL) + { + free((char *)tpCanSettings.device); + } + /* Reset transport layer settings. */ + tpCanSettings.device = NULL; + tpCanSettings.channel = 0; + tpCanSettings.baudrate = 500000; + tpCanSettings.transmitId = 0x667; + tpCanSettings.receiveId = 0x7e1; + tpCanSettings.useExtended = false; + /* This module used critical sections so terminate them. */ + UtilCriticalSectionTerminate(); } /*** end of XcpTpCanTerminate ***/ @@ -121,7 +242,11 @@ static bool XcpTpCanConnect(void) { bool result = false; - /* ##Vg TODO Implement. */ + /* Connect to the CAN driver. */ + if (CanConnect()) + { + result = true; + } /* Give the result back to the caller. */ return result; @@ -134,7 +259,8 @@ static bool XcpTpCanConnect(void) ****************************************************************************************/ static void XcpTpCanDisconnect(void) { - /* ##Vg TODO Disconnect from the CAN bus. */ + /* Disconnect from the CAN driver. */ + CanDisconnect(); } /*** end of XcpTpCanDisconnect ***/ @@ -152,7 +278,9 @@ static bool XcpTpCanSendPacket(tXcpTransportPacket const * txPacket, tXcpTransportPacket * rxPacket, uint16_t timeout) { bool result = false; - + tCanMsg canMsg; + uint32_t responseTimeoutTime = 0; + /* Check parameters. */ assert(txPacket != NULL); assert(rxPacket != NULL); @@ -160,11 +288,85 @@ static bool XcpTpCanSendPacket(tXcpTransportPacket const * txPacket, /* Only continue with valid parameters. */ if ( (txPacket != NULL) && (rxPacket != NULL) ) /*lint !e774 */ { - /* ##Vg TODO Implement. */ + /* Only continue if data length fits in a CAN message and the CAN bus is not in error + * state. + */ + if ( ((txPacket->len <= CAN_MSG_MAX_LEN)) && (!CanIsBusError()) ) + { + /* Set result value to okay and only change it from now on if an error occurred. */ + result = true; + /* Store the packet data into a CAN message. */ + canMsg.id = tpCanSettings.transmitId; + if (tpCanSettings.useExtended) + { + canMsg.id |= CAN_MSG_EXT_ID_MASK; + } + canMsg.dlc = txPacket->len; + for (uint8_t idx = 0; idx < canMsg.dlc; idx++) + { + canMsg.data[idx] = txPacket->data[idx]; + } + /* Submit the packet for transmission on the CAN bus. */ + if (!CanTransmit(&canMsg)) + { + result = false; + } + /* Only continue if the transmission was successful. */ + if (result) + { + /* Determine timeout time for the response packet. */ + responseTimeoutTime = UtilTimeGetSystemTimeMs() + timeout; + /* Poll with timeout detection to receive the response packet as a CAN message + * on the CAN bus. + */ + while (UtilTimeGetSystemTimeMs() < responseTimeoutTime) + { + /* ##Vg TODO Implement packet reception. */ + break; + } + } + } } /* Give the result back to the caller. */ return result; } /*** end of XcpTpCanSendPacket ***/ +/************************************************************************************//** +** \brief CAN driver event callback function that gets called each time a CAN +** message was transmitted. +** \param msg Pointer to the transmitted CAN message. +** +****************************************************************************************/ +static void XcpTpCanEventMessageTransmitted(tCanMsg const * msg) +{ + (void)msg; + + /* Nothing needs to be done here for now. Added for possible future expansions. */ +} /*** end of XcpTpCanEventMessageTransmitted ***/ + + +/************************************************************************************//** +** \brief CAN driver event callback function that gets called each time a CAN +** message was received. +** \param msg Pointer to the received CAN message. +** +****************************************************************************************/ +static void XcpTpCanEventMessageReceived(tCanMsg const * msg) +{ + /* Determine CAN identifier for receiving XCP commands via CAN. */ + uint32_t tpCanRxId = tpCanSettings.receiveId; + if (tpCanSettings.useExtended) + { + tpCanRxId |= CAN_MSG_EXT_ID_MASK; + } + + /* Check if the identifier matches the one for XCP on CAN. */ + if (msg->id == tpCanRxId) + { + /* ##Vg TODO process CAN message reception. */ + } +} /*** end of XcpTpCanEventMessageReceived ***/ + + /*********************************** end of xcptpcan.c *********************************/ diff --git a/Host/libopenblt.dll b/Host/libopenblt.dll index 879470e2..7f9b29fb 100644 Binary files a/Host/libopenblt.dll and b/Host/libopenblt.dll differ