/** * CAN module object for Linux socketCAN. * * This file is a template for other microcontrollers. * * @file CO_driver.h * @ingroup CO_driver * @author Janez Paternoster, Martin Wagner * @copyright 2004 - 2015 Janez Paternoster, 2017 Neuberger Gebaeudeautomation GmbH * * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . * For more information on CANopen see . * * CANopenNode is free and open source 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 2 of the * License, or (at your option) any later version. * * This program 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 should have received a copy of the GNU General Public License * along with this program. If not, see . * * Following clarification and special exception to the GNU General Public * License is included to the distribution terms of CANopenNode: * * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole combination. * * As a special exception, the copyright holders of this library give * you permission to link this library with independent modules to * produce an executable, regardless of the license terms of these * independent modules, and to copy and distribute the resulting * executable under terms of your choice, provided that you also meet, * for each linked independent module, the terms and conditions of the * license of that module. An independent module is a module which is * not derived from or based on this library. If you modify this * library, you may extend this exception to your version of the * library, but you are not obliged to do so. If you do not wish * to do so, delete this exception statement from your version. */ #ifndef CO_DRIVER_H #define CO_DRIVER_H #ifdef __cplusplus extern "C" { #endif /** * @name multi interface support * * Enable this to use interface combining at driver level. This * adds functions to broadcast/selective transmit messages on the * given interfaces as well as combining all received message into * one queue. * * This is not intended to realize interface redundancy!!! */ //#define CO_DRIVER_MULTI_INTERFACE /** * @name CAN bus error reporting * * Enable this to add support for socketCAN error detection- and * handling functions inside the driver. This is needed when you have * CANopen with "0" connected nodes as a use case, as this is normally * forbidden in CAN. * * you need to enable error reporting in your kernel driver using * "ip link set canX type can berr-reporting on". Of course, the kernel * driver for your hardware needs this functionallity to be implemented... */ //#define CO_DRIVER_ERROR_REPORTING #include "CO_driver_base.h" #include "CO_notify_pipe.h" #ifdef CO_DRIVER_ERROR_REPORTING #include "CO_error.h" #endif /** * socketCAN interface object */ typedef struct { void *CANdriverState; /**< CAN Interface identifier */ char ifName[IFNAMSIZ]; /**< CAN Interface name */ int fd; /**< socketCAN file descriptor */ #ifdef CO_DRIVER_ERROR_REPORTING CO_CANinterfaceErrorhandler_t errorhandler; #endif } CO_CANinterface_t; /** * CAN module object. It may be different in different microcontrollers. */ typedef struct{ /** List of can interfaces. From CO_CANmodule_init()/ one per CO_CANmodule_addInterface() call */ CO_CANinterface_t *CANinterfaces; uint32_t CANinterfaceCount; /** interface count */ CO_CANrx_t *rxArray; /**< From CO_CANmodule_init() */ uint16_t rxSize; /**< From CO_CANmodule_init() */ struct can_filter *rxFilter; /**< socketCAN filter list, one per rx buffer */ uint32_t rxDropCount; /**< messages dropped on rx socket queue */ CO_CANtx_t *txArray; /**< From CO_CANmodule_init() */ uint16_t txSize; /**< From CO_CANmodule_init() */ volatile bool_t CANnormal; /**< CAN module is in normal mode */ void *em; /**< Emergency object */ CO_NotifyPipe_t *pipe; /**< Notification Pipe */ int fdEpoll; /**< epoll FD */ int fdTimerRead; /**< timer handle from CANrxWait() */ #ifdef CO_DRIVER_MULTI_INTERFACE /** * Lookup tables Cob ID to rx/tx array index. Only feasible for SFF Messages. */ uint32_t rxIdentToIndex[CO_CAN_MSG_SFF_MAX_COB_ID]; /**< COB ID to index assignment */ uint32_t txIdentToIndex[CO_CAN_MSG_SFF_MAX_COB_ID]; /**< COB ID to index assignment */ #endif }CO_CANmodule_t; /** * Request CAN configuration (stopped) mode and *wait* until it is set. * * @param CANdriverState CAN module base address. */ void CO_CANsetConfigurationMode(void *CANdriverState); /** * Request CAN normal (opearational) mode and *wait* until it is set. * * @param CANmodule This object. */ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); #ifdef CO_DRIVER_MULTI_INTERFACE /** * Initialize CAN module object * * Function must be called in the communication reset section. CAN module must * be in Configuration Mode before. * * @param CANmodule This object will be initialized. * @param CANdriverState unused * @param rxArray Array for handling received CAN messages * @param rxSize Size of the above array. Must be equal to number of receiving CAN objects. * @param txArray Array for handling transmitting CAN messages * @param txSize Size of the above array. Must be equal to number of transmitting CAN objects. * @param CANbitRate not supported in this driver. Needs to be set by OS * * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT. */ #else /** * Initialize CAN module object and open socketCAN connection. * * Function must be called in the communication reset section. CAN module must * be in Configuration Mode before. * * @param CANmodule This object will be initialized. * @param CANdriverState CAN module base address. * @param rxArray Array for handling received CAN messages * @param rxSize Size of the above array. Must be equal to number of receiving CAN objects. * @param txArray Array for handling transmitting CAN messages * @param txSize Size of the above array. Must be equal to number of transmitting CAN objects. * @param CANbitRate not supported in this driver. Needs to be set by OS * * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or * CO_ERROR_SYSCALL. */ #endif CO_ReturnError_t CO_CANmodule_init( CO_CANmodule_t *CANmodule, void *CANdriverState, CO_CANrx_t rxArray[], uint16_t rxSize, CO_CANtx_t txArray[], uint16_t txSize, uint16_t CANbitRate); #ifdef CO_DRIVER_MULTI_INTERFACE /** * Add socketCAN interface to can driver * * Function must be called after CO_CANmodule_init. * * @param CANmodule This object will be initialized. * @param CANdriverState CAN module base address. * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT, * CO_ERROR_SYSCALL or CO_ERROR_INVALID_STATE. */ CO_ReturnError_t CO_CANmodule_addInterface( CO_CANmodule_t *CANmodule, void *CANdriverState); #endif /** * Close socketCAN connection. Call at program exit. * * @param CANmodule CAN module object. */ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); /** * Read CAN identifier from received message * * @param rxMsg Pointer to received message * @return 11-bit CAN standard identifier. */ uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); /** * Configure CAN message receive buffer. * * Function configures specific CAN receive buffer. It sets CAN identifier * and connects buffer with specific object. Function must be called for each * member in _rxArray_ from CO_CANmodule_t. * * @param CANmodule This object. * @param index Index of the specific buffer in _rxArray_. * @param ident 11-bit standard CAN Identifier. * @param mask 11-bit mask for identifier. Most usually set to 0x7FF. * Received message (rcvMsg) will be accepted if the following * condition is true: (((rcvMsgId ^ ident) & mask) == 0). * @param rtr If true, 'Remote Transmit Request' messages will be accepted. * @param object CANopen object, to which buffer is connected. It will be used as * an argument to pFunct. Its type is (void), pFunct will change its * type back to the correct object type. * @param pFunct Pointer to function, which will be called, if received CAN * message matches the identifier. It must be fast function. * * @return #CO_ReturnError_t: CO_ERROR_NO CO_ERROR_ILLEGAL_ARGUMENT or * CO_ERROR_OUT_OF_MEMORY (not enough masks for configuration). */ CO_ReturnError_t CO_CANrxBufferInit( CO_CANmodule_t *CANmodule, uint32_t index, uint32_t ident, uint32_t mask, bool_t rtr, void *object, void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); #ifdef CO_DRIVER_MULTI_INTERFACE /** * Check on which interface the last message for one message buffer was received * * It is in the responsibility of the user to check that this information is * useful as some messages can be received at any time on any bus. * * @param CANmodule This object. * @param ident 11-bit standard CAN Identifier. * @param [out] CANdriverStateRx message was received on this interface * @param [out] timestamp message was received at this time (system clock) * * @retval false message has never been received, therefore no base address * and timestamp are available * @retval true base address and timestamp are valid */ bool_t CO_CANrxBuffer_getInterface( CO_CANmodule_t *CANmodule, uint32_t ident, void **CANdriverStateRx, struct timespec *timestamp); #endif /** * Configure CAN message transmit buffer. * * Function configures specific CAN transmit buffer. Function must be called for * each member in _txArray_ from CO_CANmodule_t. * * @param CANmodule This object. * @param index Index of the specific buffer in _txArray_. * @param ident 11-bit standard CAN Identifier. * @param rtr If true, 'Remote Transmit Request' messages will be transmitted. * @param noOfBytes Length of CAN message in bytes (0 to 8 bytes). * @param syncFlag not supported * * @return Pointer to CAN transmit message buffer. 8 bytes data array inside * buffer should be written, before CO_CANsend() function is called. * Zero is returned in case of wrong arguments. */ CO_CANtx_t *CO_CANtxBufferInit( CO_CANmodule_t *CANmodule, uint32_t index, uint32_t ident, bool_t rtr, uint8_t noOfBytes, bool_t syncFlag); #ifdef CO_DRIVER_MULTI_INTERFACE /** * Set which interface should be used for message buffer transmission * * It is in the responsibility of the user to ensure that the correct interface * is used. Some messages need to be transmitted on all interfaces. * * If given interface is unknown or NULL is used, a message is transmitted on * all available interfaces. * * @param CANmodule This object. * @param ident 11-bit standard CAN Identifier. * @param CANdriverStateTx use this interface. NULL = not specified * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ CO_ReturnError_t CO_CANtxBuffer_setInterface( CO_CANmodule_t *CANmodule, uint32_t ident, void *CANdriverStateTx); #endif /** * Send CAN message. * * @param CANmodule This object. * @param buffer Pointer to transmit buffer, returned by CO_CANtxBufferInit(). * Data bytes must be written in buffer before function call. * * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_TX_OVERFLOW or * CO_ERROR_TX_PDO_WINDOW (Synchronous TPDO is outside window). */ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); /** * The same as #CO_CANsend(), but ensures that there is enough space remaining * in the driver for more important messages. * * The default threshold is 50%, or at least 1 message buffer. If sending * would violate those limits, #CO_ERROR_TX_OVERFLOW is returned and the * message will not be sent. * * @param CANmodule This object. * @param buffer Pointer to transmit buffer, returned by CO_CANtxBufferInit(). * Data bytes must be written in buffer before function call. * * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_TX_OVERFLOW, CO_ERROR_TX_BUSY or * CO_ERROR_TX_PDO_WINDOW (Synchronous TPDO is outside window). */ CO_ReturnError_t CO_CANCheckSend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); /** * Clear all synchronous TPDOs from CAN module transmit buffers. * This function is not supported in this driver. */ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); /** * Verify all errors of CAN module. * This function is not supported in this driver. Error checking is done * inside . */ void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); /** * Functions receives CAN messages. It is blocking. * * This function can be used in two ways * - automatic mode (call callback that is set by #CO_CANrxBufferInit() function) * - manual mode (evaluate message filters, return received message) * * Both modes can be combined. * * @param CANmodule This object. * @param fdTimer file descriptor with activated timeout. fd is not read after * expiring! -1 if not used. * @param buffer [out] storage for received message or _NULL_ * @retval >= 0 index of received message in array set by #CO_CANmodule_init() * _rxArray_, copy available in _buffer_ * @retval -1 no message received */ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buffer); #ifdef __cplusplus } #endif /*__cplusplus*/ /** @} */ #endif